Created darkice 1.3 tag in the old fashion way.

This commit is contained in:
Rafael Diniz 2016-08-04 10:47:47 -03:00
parent 80f5e746ea
commit 51062dd3bc
102 changed files with 48799 additions and 0 deletions

View File

@ -0,0 +1,48 @@
DarkIce initial author:
Akos Maroy, <darkeye@users.sourceforge.net>
DarkIce current maintainer:
Rafael Diniz, <rafael@riseup.net>
with contributions by:
Jim Crilly, <JCrilly@MSA.com>
aNa|0Gue, <analogue@glop.org>
Robin P. Blanchard, <Robin_Blanchard@gactr.uga.edu>
Tom Gray, <tomg@future-i.com>
Michael Smith, <msmith@labyrinth.net.au>
Julius O. Smith, <jos@ccrma.stanford.edu>
the OSALP team, http://osalp.sourceforge.net
Kristjan G. Bjarnason <kgb@gangverk.is>
Nicu Pavel <npavel@ituner.com>
Kai Krakow <kai@kaishome.de>
Atsuhiko Yamanaka <ymnk@jcraft.com>
Ricardo Galli <gallir@uib.es>
John Hay <jhay@icomtek.csir.co.za>
Christian Forster <forster@like.e-technik.uni-erlangen.de>
John Deeny <taqueso@dilapidated.org>
Robert Lunnon <bobl@optushome.com.au>
Enrico Ardizzoni <craken@users.sourceforge.net>
Deti Fliegl <deti@fliegl.de>
Nicholas J. Humfrey <njh@ecs.soton.ac.uk>
Joel Ebel <jbebel@ncsu.edu>
<jochen2@users.sourceforge.net>
Alexander Vlasov <zulu@galaradio.com>
Mariusz Mazur <mmazur@kernel.pl>
dsk <derrick@csociety.org>
Clyde Stubbs <clyde@htsoft.com>
Jens Maurer <Jens.Maurer@gmx.net>
Elod Horvath <elod@itfais.com>
Pierre Souchay <pierre@souchay.net>
Daniel Hazelbaker <daniel@highdesertchurch.com>
Alessandro Beretta <alessandro.baretta@radiomaria.org>
Roland Hermans <roland.hermans@omroepvenray.nl>
Sergiy <piratfm@gmail.com>
Clemens Ladisch <clemens@ladisch.de>
Edwin van den Oetelaar <oetelaar.automatisering@gmail.com>
Adrian Knoth <adi@drcomp.erfurt.thur.de>
Filipe Roque <flip.roque@gmail.com>
Johann Fot <johann.fot@dunkelfuerst.com>
Alban Peignier <alban.peignier@gmail.com>

View File

@ -0,0 +1,677 @@
All source code in the src directory is covered under the
GNU General Public License version 3 or any later version.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, 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
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state 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 program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -0,0 +1,300 @@
04-08-2016 Darkice 1.3 released
o Small bugs fixed by Nicolas Boulenguez <nicolas@debian.org>.
o Bugs related to streaming to remote servers fixed. Patch by Kalle Kulonen
<kulonenk@gmail.com> and Mark Turner <jmarkturner@gmail.com>.
15-07-2013 Darkice 1.2 released
o Issue #75: Added Ogg/Opus support. Patch by Doug Kelly
dougk.ff7@gmail.com
o Fix 'Ring Ruffer' reports.
- Increased buffer for jack to 5 seconds
- prevent darkice termination by jack, report no fatal problem when we
have a ringbuffer overflow, can happen during startup
If we can not handle input audio fast enough we just ignore the buffer
and skip it, and just report it.
- new multithreaded connector code, now handles encoders in parallel
and does not spin waiting, cpu load will be very much lower now
Codes uses 2 condition variables to report data availability and
consumer thread availability
- Hopes are that glitching reports will be a thing of the past
- minor compiler warnings fixed
(Fix by Edwin van den Oetelaar)
o Issue #56: Wrong icecast2 password isn't properly reported, fixed.
thanks to Filipe Roque <flip.roque@gmail.com>
o Issue #57: BufferedSink makes streams invalid, fixed.
thanks to Alban Peignier <alban.peignier@gmail.com>
o Issue #30: Segmentation Fault when creating file with fileAddDate, fixed
thanks to Filipe Roque <flip.roque@gmail.com>
27-10-2011 Darkice 1.1 released
o Updated aac+ encoding to use libaacplus-2.0.0 api.
thanks to Sergiy <piratfm@gmail.com>
o Added pulseaudio support
closes ticket #25
thanks to Filipe Roque <flip.roque@gmail.com> and
and Johann Fot <johann.fot@dunkelfuerst.com>
o Added rtprio parameter and revisited realtime priority
closes ticket #21
thanks to Adrian Knoth <adi@drcomp.erfurt.thur.de>
o Fixed a call to a deprecated jack call
closes ticket #22
thanks to Adrian Knoth again.
09-05-2010 Darkice 1.0 released
o fixed a bug in BufferedSink.cpp that leads to some buffers
being written twice, causing corruption of datastream,
closes ticked #20
thanks to Edwin van den Oetelaar <oetelaar.automatisering@gmail.com>
o implemented samplerate conversion for all codecs using libsamplerate,
and keeping internal aflibConverter as fallback,
thanks to Sergiy <piratfm@gmail.com>
o bugfix: fix for alsa driver - closes ticked #8
thanks to Clemens Ladisch <clemens@ladisch.de>
14-11-2009 Darkice 0.20.1 released
o added rc.darkice init script
thanks to Niels Dettenbach <nd@syndicat.com>
o bugfix: fix for gcc 4.4
05-11-2009 Darkice 0.20 released
o new maintainer: Rafael Diniz <rafael@riseup.net>
o added AAC HEv2 encoding support (branch darkice-aacp merged) through
libaacplus, http://tipok.org.ua/ru/node/17
thanks to tipok <piratfm@gmail.com> and others for the contribution.
o bugfix: the configure script recognizes Ogg Vorbis shared objects
now, not just static libraries. Thanks to omroepvenray.
o bugfix: enabling jack source compilation on Debian Lenny,
thanks to Alessandro Beretta <alessandro.baretta@radiomaria.org>
07-07-2008 Darkice 0.19 released
o added mount point option for Darwin Streaming Server
thanks to Pierre Souchay <pierre@souchay.net>
o fix for some reliablity issues when using a Jack source
thanks to Pierre Souchay <pierre@souchay.net>
o enable easier finding of jack libraries on MacOS X,
thanks to Daniel Hazelbaker <daniel@highdesertchurch.com>
o added ability to specify name of jack device created by darkice,
thanks to Alessandro Beretta <alessandro.baretta@radiomaria.org>
26-04-2007 DarkIce 0.18.1 released
o enable real-time scheduling for non-super-users, if they have
the proper operating system permissions,
thanks to Jens Maurer <Jens.Maurer@gmx.net>
o fix to enable compliation of the Serial ULAW code on MacOS X,
thanks to Elod Horvath <elod@itfais.com>
o fix to solve Shoutcast login failures, introduced in 0.18
05-03-2007 DarkIce 0.18 released
o added serial ulaw input device support, thanks to
Clyde Stubbs <clyde@htsoft.com>
o improvements on reconnecting:
added TCP connection keep-alive to TCP sockets
added graceful sleep when trying to reconnect
o added user-defined date formatting for the fileAddDate options,
thanks to dsk <derrick@csociety.org>
o added logging facility - [file-X] targets will cut the saved file
and rename it as needed when darkice recieves the SIGUSR1 signal
o added default configuration file handling - if no configuration file
is specified, /etc/darkice.cfg is used
o fix to enable compiling on 64 bit platforms
thanks to Alexander Vlasov <zulu@galaradio.com> and
Mariusz Mazur <mmazur@kernel.pl>
o fix to enable file dump feature using ogg vorbis.
thanks to dsk <derrick@csociety.org>
o fix to enable compiling with jack installed at arbitrary locations
19-05-2006 DarkIce 0.17.1 released
o bugfix: automatic reconnect works more reliably
26-01-2006 DarkIce 0.17 released
o added check for bufferSecs set to 0
thanks to Toph <fangiotophia@gmail.com>
o added realtime parameter to the general section
o added MPEG2 support through the TwoLame library.
thanks to Nicholas J Humfrey <njh@ecs.soton.ac.uk>
22-10-2005 DarkIce 0.16 released
o added AAC support through the faac codec, http://www.audiocoding.com
o bug fix: icecast2 sections didn't honor lowpass or highpass filters
when using the mp3 format
14-04-2005 DarkIce 0.15 released
o ported to OpenBSD and NetBSD, though real-time scheduling not supported,
since it is not implemented in OpenBSD / NetBSD
o added possibility to downsample from stereo to mono when encoding
to Ogg Vorbis, thanks to Deti Fliegl, <deti@fliegl.de>
o added support for Jack inputs, enabling a lot of interesting usage,
including support for MacOS X.
Thanks to Nicholas J. Humfrey <njh@ecs.soton.ac.uk>
o various improvements by Joel Ebel <jbebel@ncsu.edu>
o added option to turn off automatic reconnect feature
o added IPv6 support, thanks to <jochen2@users.sourceforge.net>
15-02-2004: DarkIce 0.14 released
o added ALSA support, thanks to Christian Forster
<forster@like.e-technik.uni-erlangen.de>
o added fix to enable downsampling from stereo to mono of mp3 streams
when streaming to an icecast2 server. thanks to John Deeny
<taqueso@dilapidated.org>
o removed _X and _Y symbols from aflibConverter files, which caused
a naming collision on Solaris. thanks to Robert Lunnon,
<bobl@optushome.com.au>
o bug fix: ogg vorbis recording to only a file caused a segfault.
now fixed, thanks to Enrico Ardizzoni <craken@users.sourceforge.net>
07-01-2004: DarkIce 0.13.2 released
o bug fix: two bugs fixed that caused core dump when encoding into
mp3 of FreeBSD. thanks to John Hay <jhay@icomtek.csir.co.za>
o added configure option --with-debug to enable compilation for debug mode
12-02-2003: Darkice 0.13.1 released
o added cross-platform pthread detection, thanks to
Steven G. Johnson <stevenj@alum.mit.edu> and
Alejandro Forero Cuervo <bachue@bachue.com>
see http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html
o added proper detection of netural endiannes for 16 bit recording
o basically these changes allow compilation on FreeBSD
09-02-2003: DarkIce 0.13 released
o added feature for setting the TITLE comment field for vorbis
streams. thanks to Ricardo Galli <gallir@uib.es>
o bugfix: fixed minor bug in IcecCast2.cpp, which could have lead to
a buffer overflow. thanks to Atsuhiko Yamanaka <ymnk@jcraft.com>
o bugfix: MultiThreadedConnector::sinkThread() was private, now public
o added fileAddDate configuration option
thanks to Nicu Pavel <npavel@ituner.com>
o added support for big endian OSS devices (like Linux PowerPC)
20-10-2002: DarkIce 0.12 released
o ported to FreeBSD (removed reference to MSG_NOSIGNAL in TcpSocket.cpp)
o bug fix: maximum bitrate setting fixed for Ogg Vorbis streams
o changed internals so that now each encoding/server connection is
a separate thread
o when a connection is dropped, DarkIce tries to reconnect, indefinitely
20-08-2002: DarkIce 0.11 released
o added possibility to specify maximum bitrate for Ogg Vorbis streams
o added HTTP Basic authentication for icecast2 logins
o added mp3 streaming for icecast2
o added possibility to stream in mono even when recording in stereo,
thus enabling mono and stereo streams with the same darkice instance.
only for mp3 streams at the moment
thanks to Kai Krakow <kai@kaishome.de>
o bug fix: resampling audio for vorbis streams bugs fixed
02-08-2002: DarkIce 0.10.1 released
o bug fix: when the last server dropped connection, darkice crashed
thanks to Nicu Pavel <npavel@ituner.com>
o bug fix for LameLibEncoder: the mp3 encoding buffer was deleted too
early, resulting in mp3 data corruption.
thanks to Nicu Pavel <npavel@ituner.com>
20-07-2002: DarkIce 0.10 released
o added possibility to select constant, average and variable bit rate
encoding modes with specifying encoding quality as well.
thanks to Nicu Pavel <npavel@ituner.com>
o added support for Ogg Vorbis 1.0 final, removed support for rc2
o added fault tolerance: if one of several server connection drops,
DarkIce carries on with the rest of the servers still connected
09-04-2002: DarkIce 0.9.1 released
o bugfix: a memory leak was introduced in 0.9, which is fixed thanks to
Kristjan G. Bjarnason <kgb@gangverk.is> and Nicu Pavel <npavel@ituner.com>
o minor documentation fix
28-03-2002: DarkIce 0.9 released
o added possibility to simply read from the soundcard, encode, and
save the encoded data into a local file (no streaming server needed)
o added variable bitrate support for vorbis streams
o support for both rc2 and rc3 versions of vorbis libraries
o added support for resampling when encoding to vorbis
thanks to the OSALP project for the resampling class,
http://osalp.sourceforge.net/ and
Julius O. Smith, <jos@ccrma.stanford.edu> for the original code
20-02-2002: DarkIce 0.8 released
o added possibility to disable lowpass and highpass filtering for lame
o fixed incorrect vorbis bitrate setting
o fix: DarkIce now reports public streams correctly
thanks to Tom Gray, <tomg@future-i.com>
o made up-to-date with Ogg Vorbis rc3 libs
thanks to Michael Smith, <msmith@labyrinth.net.au>
o made up-to-date with current IceCast2 cvs version
o added local stream dump possibility
19-10-2001: DarkIce 0.7 released
o added support for FreeBSD
thanks to Robin P. Blanchard, <Robin_Blanchard@gactr.uga.edu>
o added support for resampling mp3 streams
o DarkIce config file now may contain spaces and tabs as white space
o configure script enables build with or without lame / Ogg Vorbis
also possibility to specify alternate locations for these
18-09-2001: DarkIce 0.6 released
o added support for IceCast2 server with Ogg Vorbis streaming
Ogg Vorbis support thanks to aNa|0Gue <analogue@glop.org>
o added support for SUN Solaris
o removed long command line options (as these are extensions to UNIX)
o removed configure option to specify location of lame library
o removed configure option to compile static executable
09-09-2001: DarkIce 0.5 released
o added support for ShoutCast servers
o removed local copy of SGI STL, uses STL of the C++ compiler
o compiles with gcc3-c++
o added man page darkice.cfg.5
o bugfix: config files can have comments before the first section
02-09-2001: DarkIce 0.4 released
o support for external command line encoder removed, replaced
with using lame as a shared object or statically linked library
o added darkice man page
o created RPM packages
o DarkIce no longer reports an error if the sound card recording
sample rate could not be set to the exact specified amount
(e.g. the sound card reports 44101 Hz instead of 44100 Hz)
26-08-2001: DarkIce 0.3.1 released
o support for unlimited time encoding
thanks to Jim Crilly, <JCrilly@MSA.com>
20-12-2000: DarkIce 0.3 released
o added POSIX real-time scheduling
18-11-2000: DarkIce 0.2 released
o code cleanup
o first real tests made
o added verbosity command line option
13-11-2000: DarkIce 0.1 released

View File

@ -0,0 +1,21 @@
DarkIce Frequenty Asked Questions
Q: I get the following error:
DarkIce: LameLibEncoder.cpp:75: lame lib opening underlying sink error [0]
What am I doing wrong?
A: This error means (quite anti-intuitively), that darkice coulnd't connect
to the streaming server. Please double-check the following values in
your config file:
- server
- port
- password
If you're streaming to a shoutcast server, make sure that the port
you use is the _source_ port, which is usually 1 above the _client_
port for shoutcast (the defaults are 8000 for client, 8001 for source).

View File

@ -0,0 +1,52 @@
Installing Lame
---------------
To install DarkIce, you need the Lame 3.89 or later libraries and
related header files already installed on your system.
It is recommended that use install Lame to the usual system locations,
/usr/lib, /usr/include, so that DarkIce will find the header files and
libraries. Thus when configuring, add --prefix=/usr to the configure
options.
Grab the latest lame source tarball from a download site found at
http://www.mp3dev.org/mp3/download/download.html
or from the DarkIce SourceForge project download area
http://sourceforge.net/project/showfiles.php?group_id=14111
I took lame lame-3.91.tar.gz. Go to the directory where you saved it,
and issue the following commands:
tar xfz lame-3.91.tar.gz
cd lame-3.91
./configure --with-fileio=lame --without-vorbis --disable-gtktest --enable-expopt=full --prefix=/usr
make
make install
For the last step, you need to be root or have write permissions in the
target directories.
You might consider using nasm if you're on a i386 system, with the
configure option --enable-nasmm, for maximum performance.
On RedHat Linux
---------------
Compiling Lame on RedHat Linux is a tricky issue, because of gcc 2.96
packaged with the distributions 7.0 and 7.1. You either have to use
the comaptibility compiler package (compat-egcs and related packages,
providing gcc 2.91), or even better, gcc 3.0.
It is recommended that you compile lame with gcc 3. For maximum performance,
use the nasm assembler to compile assembly optimizations into lame.
Try the following commands:
tar xfz lame-3.91.tar.gz
cd lame-3.91
export CC=gcc3
./configure --with-fileio=lame --without-vorbis --disable-gtktest --enable-nasm --enable-expopt=full --prefix=/usr
make
make install

View File

@ -0,0 +1,39 @@
Installing Ogg Vorbis
---------------------
To install DarkIce, you need the following Ogg Vorbis 1.0 or later
libraries (and related header files):
- libogg
- libvoribs
- libvorbisenc
installed on your system.
It is recommended that use install these to the usual system locations,
/usr/lib, /usr/include, so that DarkIce will find the header files and
libraries. Thus when configuring, add --prefix=/usr to the configure
options.
Grab the latest Ogg Vorbis tarballs from
http://www.xiph.org/ogg/vorbis/download.html
I took libogg-1.0.tar.gz and libvorbis-1.0.tar.gz. Go to the
directory where you saved them, and issue the following commands:
tar xfz libogg-1.0.tar.gz
cd libogg-1.0
./configure --prefix=/usr
make
make install
cd ..
tar xfz libvorbis-1.0.tar.gz
cd libvorbis-1.0
./configure --prefix=/usr
make
make install
For the install steps, you need to be root or have write permissions in the
target directories.

View File

@ -0,0 +1,7 @@
SUBDIRS = src man
sysconf_DATA = darkice.cfg
EXTRA_DIST = darkice.cfg INSTALL.lame INSTALL.vorbis FAQ rc.darkice

View File

@ -0,0 +1,136 @@
14-11-2009, Rafael Diniz, rafael@riseup.net
Released version 0.20.1. See ChangeLog for changes.
05-11-2009, Rafael Diniz, rafael@riseup.net
Released version 0.20. See ChangeLog for changes.
07-07-2008, Akos Maroy, darkeye@tyrell.hu
Released version 0.19. See ChangeLog for changes.
26-04-2007, Akos Maroy, darkeye@tyrell.hu
Released version 0.18.1. See ChangeLog for changes.
05-03-2007, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.18. See ChangeLog for changes.
19-05-2006, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.17.1. See ChangeLog for changes.
26-01-2006, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.17. See ChangeLog for changes.
22-10-2005, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.16. See ChangeLog for changes.
14-04-2005, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.15. See ChangeLog for changes.
15-02-2004, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.14. See ChangeLog for changes.
07-01-2004, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.13.2. See ChangeLog for changes.
12-02-2003, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.13.1. See ChangeLog for changes.
09-02-2003, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.13. See ChangeLog for changes.
20-10-2002, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.12. See ChangeLog for changes.
20-08-2002, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.11. See ChangeLog for changes.
02-08-2002, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.10.1. See ChangeLog for changes.
20-07-2002, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.10. See ChangeLog for changes.
09-04-2002, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.9.1. See ChangeLog for changes.
28-03-2002, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.9. See ChangeLog for changes.
20-02-2002, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.8. See ChangeLog for changes.
19-10-2001, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.7. See ChangeLog for changes.
18-09-2001, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.6. See ChangeLog for changes.
09-09-2001, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.5. See ChangeLog for changes.
02-09-2001, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.4. See ChangeLog for changes.
26-08-2001, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.3.1. See ChangeLog for changes.
20-12-2000, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.3. See ChangeLog for changes.
18-11-2000, Akos Maroy, darkeye@users.sourceforge.net
Released version 0.2. See ChangeLog for changes.
13-11-2000, Akos Maroy, darkeye@users.sourceforge.net
Initial release. Supports the lame encoder.

View File

@ -0,0 +1,75 @@
DarkIce live audio streamer, http://www.darkice.org/
Copyright (c) 2000-2007, Tyrell Hungary, http://tyrell.hu/
Copyright (c) 2008, Ákos Maróy, akos@maroy.hu
Copyright (c) 2009, Rafael Diniz, rafael@riseup.net
Contents
--------
1. What is DarkIce?
2. Compiling and installing
3. Reporting crashes
1. What is DarkIce?
-------------------
DarkIce is an IceCast, IceCast2 and ShoutCast live audio streamer. It
takes audio input from a sound card, encodes it into mp3 and/or Ogg Vorbis,
and sends the mp3 stream to one or more IceCast and/or ShoutCast servers,
the Ogg Vorbis stream to one or more IceCast2 servers.
DarkIce website: http://www.darkice.org/
2. Compiling and installing
---------------------------
On how to compile and install, please read the file INSTALL. If you're
impatient, try:
./configure
make
The executable built is src/darkice.
To install, try as root:
make install
For documentation, try:
man darkice
3. Reporting crashes
--------------------
When DarkIce core dumps, please send the backtrace along with your error
report to the darkice mailing list: http://www.freelists.org/list/darkice
Alternatively you could file a bug report at http://www.darkice.org/
To get the backtrace information, you need gdb, the GNU debugger:
1. configure and compile using the --with-debug option:
./configure --with-debug=yes
make clean all
2. run darkice from within gdb:
gdb src/darkice
3. set parameters within gdb:
(gdb) set args -c darkice.cfg
4. run:
(gdb) run
5. after coredump, print the backtrace:
(gdb) bt

View File

@ -0,0 +1,13 @@
o Add samplerate conversion for samplerate audio output different from audio source
o Add Coreaudio support
o change Ref to follow inheritance
o make a master config file, and a small one ?
o add support for multiple servers for one stream ?
o revisit real-time scheduling
o look into performance
o create proper error-reporting module
o set comment fields for Ogg Vorbis streams as in
http://www.xiph.org/ogg/vorbis/doc/v-comment.html
o change config file to separate descriptions of input, streams and
stream targets (servers, files, etc.)
o add support for 24 and 32 bit input and higher sample rates (up to 96kHz)

View File

@ -0,0 +1,299 @@
dnl acinclude.m4. Change *this* file to add new or change macros.
dnl When changes have been made, delete aclocal.m4 and run
dnl "aclocal".
dnl
dnl DO NOT change aclocal.m4 !
dnl
dnl-----------------------------------------------------------------------------
dnl LA_SEARCH_FILE(variable, filename, PATH)
dnl Search "filename" in the specified "PATH", "variable" will
dnl contain the full pathname or the empty string
dnl PATH is space-separated list of directories.
dnl by Florian Bomers
dnl-----------------------------------------------------------------------------
AC_DEFUN([LA_SEARCH_FILE],[
$1=
dnl hack: eliminate line feeds in $2
for FILE in $2; do
for DIR in $3; do
dnl use PATH in order
if test ".$1"="." && test -f "$DIR/$FILE"; then
$1=$DIR
fi
done
done
])
dnl-----------------------------------------------------------------------------
dnl LA_SEARCH_LIB(lib-variable, include-variable, lib-filename, header-filename, prefix)
dnl looks for "lib-filename" and "header-filename" in the area of "prefix".
dnl if found, "lib-variable" and "include-variable" are set to the
dnl respective paths.
dnl prefix is a single path
dnl libs are searched in prefix, prefix/lib
dnl headers are searched in prefix, prefix/include,
dnl
dnl If one of them is not found, both "lib-variable", "include-variable" are
dnl set to the empty string.
dnl
dnl TODO: assert function call to verify lib
dnl
dnl by Florian Bomers
dnl-----------------------------------------------------------------------------
AC_DEFUN([LA_SEARCH_LIB],[
dnl look for lib
LA_SEARCH_FILE($1, $3, $5 $5/lib64 $5/lib $5/lib/x86_64-linux-gnu )
dnl look for header.
LA_SEARCH_FILE($2, $4, $5 $5/include )
if test ".$1" = "." || test ".$2" = "."; then
$1=
$2=
fi
])
dnl-----------------------------------------------------------------------------
dnl funky posix threads checking, thanks to
dnl Steven G. Johnson <stevenj@alum.mit.edu>
dnl and Alejandro Forero Cuervo <bachue@bachue.com>
dnl see http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html
dnl-----------------------------------------------------------------------------
dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
dnl
dnl This macro figures out how to build C programs using POSIX
dnl threads. It sets the PTHREAD_LIBS output variable to the threads
dnl library and linker flags, and the PTHREAD_CFLAGS output variable
dnl to any special C compiler flags that are needed. (The user can also
dnl force certain compiler flags/libs to be tested by setting these
dnl environment variables.)
dnl
dnl Also sets PTHREAD_CC to any special C compiler that is needed for
dnl multi-threaded programs (defaults to the value of CC otherwise).
dnl (This is necessary on AIX to use the special cc_r compiler alias.)
dnl
dnl NOTE: You are assumed to not only compile your program with these
dnl flags, but also link it with them as well. e.g. you should link
dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
dnl
dnl If you are only building threads programs, you may wish to
dnl use these variables in your default LIBS, CFLAGS, and CC:
dnl
dnl LIBS="$PTHREAD_LIBS $LIBS"
dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
dnl CC="$PTHREAD_CC"
dnl
dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE
dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
dnl
dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands
dnl to run it if it is not found. If ACTION-IF-FOUND is not specified,
dnl the default action will define HAVE_PTHREAD.
dnl
dnl Please let the authors know if this macro fails on any platform,
dnl or if you have any other suggestions or comments. This macro was
dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org)
dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread
dnl macros posted by AFC to the autoconf macro repository. We are also
dnl grateful for the helpful feedback of numerous users.
dnl
dnl @version $Id$
dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Alejandro Forero Cuervo <bachue@bachue.com>
AC_DEFUN([ACX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_SAVE
AC_LANG_C
acx_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
AC_MSG_RESULT($acx_pthread_ok)
if test x"$acx_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all.
acx_pthread_flags="pthread-config pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthread-config: use pthread-config program (on NetBSD)
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# pthread: Linux, etcetera
# --thread-safe: KAI C++
case "${host_cpu}-${host_os}" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthread or
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
;;
esac
if test x"$acx_pthread_ok" = xno; then
for flag in $acx_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
if test x"$acx_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[acx_pthread_ok=yes])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($acx_pthread_ok)
if test "x$acx_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$acx_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: threads are created detached by default
# and the JOINABLE attribute has a nonstandard name (UNDETACHED).
AC_MSG_CHECKING([for joinable pthread attribute])
AC_TRY_LINK([#include <pthread.h>],
[int attr=PTHREAD_CREATE_JOINABLE;],
ok=PTHREAD_CREATE_JOINABLE, ok=unknown)
if test x"$ok" = xunknown; then
AC_TRY_LINK([#include <pthread.h>],
[int attr=PTHREAD_CREATE_UNDETACHED;],
ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)
fi
if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then
AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok,
[Define to the necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_RESULT(${ok})
if test x"$ok" = xunknown; then
AC_MSG_WARN([we do not know how to create joinable pthreads])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "${host_cpu}-${host_os}" in
*-aix* | *-freebsd*) flag="-D_THREAD_SAFE";;
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with cc_r
AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$acx_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
acx_pthread_ok=no
$2
fi
AC_LANG_RESTORE
])dnl ACX_PTHREAD

View File

@ -0,0 +1,69 @@
#!/bin/sh
# Run this to set up the build system: configure, makefiles, etc.
# (based on the version in enlightenment's cvs)
package="darkice"
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
cd "$srcdir"
DIE=0
(autoheader --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have autoconf installed to compile $package."
echo "Download the appropriate package for your distribution,"
echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have autoconf installed to compile $package."
echo "Download the appropriate package for your distribution,"
echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
(automake --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have automake installed to compile $package."
echo "Download the appropriate package for your system,"
echo "or get the source from one of the GNU ftp sites"
echo "listed in http://www.gnu.org/order/ftp.html"
DIE=1
}
(libtool --help) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have libtool installed to compile $package."
echo "Download the appropriate package for your system,"
echo "or get the source from one of the GNU ftp sites"
echo "listed in http://www.gnu.org/order/ftp.html"
DIE=1
}
if test "$DIE" -eq 1; then
exit 1
fi
if test -z "$*"; then
echo "I am going to run ./configure with no arguments - if you wish "
echo "to pass any to it, please specify them on the $0 command line."
fi
echo "Generating configuration files for $package, please wait...."
echo " aclocal $ACLOCAL_FLAGS"
aclocal $ACLOCAL_FLAGS
echo " autoheader"
autoheader
echo " libtoolize --automake"
libtoolize --automake
echo " automake --add-missing $AUTOMAKE_FLAGS"
automake --add-missing $AUTOMAKE_FLAGS
echo " autoconf"
autoconf
$srcdir/configure "$@" && echo

View File

@ -0,0 +1,271 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(darkice, 1.3)
AC_CONFIG_SRCDIR(src/DarkIce.cpp)
AM_CONFIG_HEADER(src/config.h)
AM_INIT_AUTOMAKE
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
PKG_PROG_PKG_CONFIG
dnl AC_STDC_HEADERS
AC_HAVE_HEADERS(errno.h fcntl.h stdio.h stdlib.h string.h unistd.h limits.h)
AC_HAVE_HEADERS(signal.h time.h sys/time.h sys/types.h sys/wait.h math.h)
AC_HAVE_HEADERS(netdb.h netinet/in.h sys/ioctl.h sys/socket.h sys/stat.h)
AC_HAVE_HEADERS(sched.h pthread.h termios.h)
AC_HAVE_HEADERS(sys/soundcard.h sys/audio.h sys/audioio.h)
AC_HEADER_SYS_WAIT()
AC_TYPE_PID_T()
AC_TYPE_SIZE_T()
AC_C_BIGENDIAN()
AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(nsl, gethostbyname)
AC_CHECK_LIB(rt, sched_getscheduler)
AC_CHECK_FUNC(getaddrinfo, AC_DEFINE(HAVE_GETADDRINFO, 1, [Does function getaddrinfo exist?] ))
dnl-----------------------------------------------------------------------------
dnl funky posix threads checking, thanks to
dnl Steven G. Johnson <stevenj@alum.mit.edu>
dnl and Alejandro Forero Cuervo <bachue@bachue.com>
dnl see http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html
dnl-----------------------------------------------------------------------------
ACX_PTHREAD(, AC_MSG_ERROR( [pthread library not found] ))
SYSTEM_INCLUDE=/usr/include
dnl-----------------------------------------------------------------------------
dnl link the lame library if requested
dnl-----------------------------------------------------------------------------
AC_SUBST(LAME_CFLAGS)
AC_SUBST(LAME_LIBS)
AC_ARG_WITH(lame,
AS_HELP_STRING([--with-lame], [use lame for encoding mp3 streams @<:@check@:>@]),
[], with_lame=check)
AC_ARG_WITH(lame-prefix,
AS_HELP_STRING([--with-lame-prefix=DIR],
[alternate location for lame @<:@/usr@:>@.
Look for libraries in LAME-PREFIX/lib,
for headers in LAME-PREFIX/include]),
CONFIG_LAME_PREFIX="${withval}", CONFIG_LAME_PREFIX="/usr")
if test "x$with_lame" != xno ; then
AC_MSG_CHECKING( [for lame library at ${CONFIG_LAME_PREFIX}] )
LA_SEARCH_LIB( LAME_LIB_LOC, LAME_INC_LOC, libmp3lame.a libmp3lame.so, lame/lame.h,
${CONFIG_LAME_PREFIX})
if test "x${LAME_LIB_LOC}" != "x" ; then
AC_DEFINE( HAVE_LAME_LIB, 1, [build with lame library] )
if test "x${LAME_INC_LOC}" != "x${SYSTEM_INCLUDE}" ; then
LAME_CFLAGS="-I${LAME_INC_LOC}"
fi
LAME_LIBS="-L${LAME_LIB_LOC} -lmp3lame"
AC_MSG_RESULT( [found at ${CONFIG_LAME_PREFIX}] )
elif test "x$with_lame" = xyes ; then
AC_MSG_ERROR([unable to find lame library])
else
AC_MSG_WARN( [not found, building without lame])
fi
else
AC_MSG_RESULT( [building without lame] )
fi
dnl-----------------------------------------------------------------------------
dnl link the ogg vorbis libraries if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(vorbis,
AS_HELP_STRING([--with-vorbis], [use Ogg Vorbis for encoding vorbis streams @<:@check@:>@]),
[], with_vorbis=check)
AS_CASE([$with_vorbis],
check, [PKG_CHECK_MODULES(VORBIS, [ogg vorbis vorbisenc], [], true)],
yes, [PKG_CHECK_MODULES(VORBIS, [ogg vorbis vorbisenc])],
AC_MSG_RESULT([building without Ogg Vorbis]))
AS_IF(test -n "$VORBIS_LIBS",
AC_DEFINE(HAVE_VORBIS_LIB, 1, [build with Ogg Vorbis library]))
dnl-----------------------------------------------------------------------------
dnl link the ogg / opus libraries if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(opus,
AS_HELP_STRING([--with-opus], [use Ogg Opus for encoding opus streams @<:@check@:>@]),
[], with_opus=check)
AS_CASE([$with_opus],
check, [PKG_CHECK_MODULES(OPUS, [ogg opus], [], true)],
yes, [PKG_CHECK_MODULES(OPUS, [ogg opus])],
AC_MSG_RESULT([building without Ogg Opus]))
AS_IF(test -n "$OPUS_LIBS",
AC_DEFINE(HAVE_OPUS_LIB, 1, [build with Ogg Opus library]))
dnl-----------------------------------------------------------------------------
dnl link the faac library if requested
dnl-----------------------------------------------------------------------------
AC_SUBST(FAAC_CFLAGS)
AC_SUBST(FAAC_LIBS)
AC_ARG_WITH(faac,
AS_HELP_STRING([--with-faac], [use faac for encoding AAC streams @<:@check@:>@]),
[], with_faac=check)
AC_ARG_WITH(faac-prefix,
AS_HELP_STRING([--with-faac-prefix=DIR],
[alternate location for faac @<:@/usr@:>@.
Look for libraries in FAAC-PREFIX/lib,
for headers in FAAC-PREFIX/include]),
CONFIG_FAAC_PREFIX="${withval}", CONFIG_FAAC_PREFIX="/usr")
if test "x$with_faac" != xno ; then
AC_MSG_CHECKING( [for faac library at ${CONFIG_FAAC_PREFIX}] )
LA_SEARCH_LIB( FAAC_LIB_LOC, FAAC_INC_LOC, libfaac.a libfaac.so, faac.h,
${CONFIG_FAAC_PREFIX})
if test "x${FAAC_LIB_LOC}" != "x" ; then
AC_DEFINE( HAVE_FAAC_LIB, 1, [build with faac library] )
if test "x${FAAC_INC_LOC}" != "x${SYSTEM_INCLUDE}" ; then
FAAC_CFLAGS="-I${FAAC_INC_LOC}"
fi
FAAC_LIBS="-L${FAAC_LIB_LOC} -lfaac"
AC_MSG_RESULT( [found at ${CONFIG_FAAC_PREFIX}] )
elif test "x$with_faac" = yes ; then
AC_MSG_ERROR([unable to find faac library])
else
AC_MSG_WARN( [not found, building without faac])
fi
else
AC_MSG_RESULT( [building without faac] )
fi
dnl-----------------------------------------------------------------------------
dnl link the aacplus library if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(aacplus,
AS_HELP_STRING([--with-aacplus], [use aacplus for encoding AAC HEv2 streams @<:@check@:>@]),
[], with_aacplus=check)
AS_CASE([$with_aacplus],
check, [PKG_CHECK_MODULES(AACPLUS, aacplus, [], true)],
yes, [PKG_CHECK_MODULES(AACPLUS, aacplus)],
AC_MSG_RESULT([building without aacplus]))
AS_IF(test -n "$AACPLUS_LIBS",
AC_DEFINE(HAVE_AACPLUS_LIB, 1, [build with aacplus library]))
dnl-----------------------------------------------------------------------------
dnl link the twolame library if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(twolame,
AS_HELP_STRING([--with-twolame], [use twolame for encoding MP2 streams @<:@check@:>@]),
[], with_twolame=check)
AS_CASE([$with_twolame],
check, [PKG_CHECK_MODULES(TWOLAME, twolame, [], true)],
yes, [PKG_CHECK_MODULES(TWOLAME, twolame)],
AC_MSG_RESULT([building without twolame]))
AS_IF(test -n "$TWOLAME_LIBS",
AC_DEFINE(HAVE_TWOLAME_LIB, 1, [build with twolame library]))
dnl-----------------------------------------------------------------------------
dnl make sure at least one of lame and vorbis present
dnl-----------------------------------------------------------------------------
if test -z "x${LAME_LIBS}" \
-a -z "${VORBIS_LIBS}" \
-a -z "${OPUS_LIBS}" \
-a -z "${FAAC_LIBS}" \
-a -z "${AACPLUS_LIBS}" \
-a -z "${TWOLAME_LIBS}" ; then
AC_MSG_ERROR([neither lame, Ogg Vorbis, opus, faac, aac+ nor twolame configured])
fi
dnl-----------------------------------------------------------------------------
dnl link ALSA sound system if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(alsa,
AS_HELP_STRING([--with-alsa], [use ALSA sound system @<:@check@:>@]),
[], with_alsa=check)
AS_CASE([$with_alsa],
check, [PKG_CHECK_MODULES(ALSA, alsa, [], true)],
yes, [PKG_CHECK_MODULES(ALSA, alsa)],
AC_MSG_RESULT([building without ALSA support]))
AS_IF(test -n "$ALSA_LIBS",
AC_DEFINE(HAVE_ALSA_LIB, 1, [build with ALSA sound system]))
dnl-----------------------------------------------------------------------------
dnl link PULSEAUDIO sound system if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(pulseaudio,
AS_HELP_STRING([--with-pulseaudio], [use PULSEAUDIO sound system @<:@check@:>@]),
[], with_pulseaudio=check)
AS_CASE([$with_pulseaudio],
check, [PKG_CHECK_MODULES(PULSEAUDIO, libpulse-simple libpulse, [], true)],
yes, [PKG_CHECK_MODULES(PULSEAUDIO, libpulse-simple libpulse)],
AC_MSG_RESULT([building without PULSEAUDIO support]))
AS_IF(test -n "$PULSEAUDIO_LIBS",
AC_DEFINE(HAVE_PULSEAUDIO_LIB, 1, [build with PULSEAUDIO sound system]))
dnl-----------------------------------------------------------------------------
dnl link JACK sound server if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(jack,
AS_HELP_STRING([--with-jack], [use JACK sound system @<:@check@:>@]),
[], with_jack=check)
AS_CASE([$with_jack],
check, [PKG_CHECK_MODULES(JACK, jack, [], true)],
yes, [PKG_CHECK_MODULES(JACK, jack)],
AC_MSG_RESULT([building without JACK support]))
AS_IF(test -n "$JACK_LIBS",
AC_DEFINE(HAVE_JACK_LIB, 1, [build with JACK audio server support]))
dnl-----------------------------------------------------------------------------
dnl link Secret Rabbit Code (aka libsamplerate) if requested
dnl-----------------------------------------------------------------------------
AC_ARG_WITH(samplerate,
AS_HELP_STRING([--with-samplerate], [use Secret Rabbit Code (aka libsamplerate) for samplerate conversion @<:@check@:>@]),
[], with_samplerate=check)
AS_CASE([$with_samplerate],
check, [PKG_CHECK_MODULES(SRC, samplerate, [], true)],
yes, [PKG_CHECK_MODULES(SRC, samplerate)],
AC_MSG_RESULT([building without libsamplerate support]))
AS_IF(test -n "$SRC_LIBS",
AC_DEFINE(HAVE_SRC_LIB, 1, [build with samplerate conversion through libsamplerate]))
AM_CONDITIONAL(HAVE_SRC_LIB, test -n "${SRC_LIBS}")
dnl-----------------------------------------------------------------------------
dnl check for MSG_NOSIGNAL for the send() function in libsocket
dnl-----------------------------------------------------------------------------
AC_MSG_CHECKING(for MSG_NOSIGNAL)
AC_TRY_COMPILE([#include <sys/socket.h>], [
int f = MSG_NOSIGNAL;
], [
# Yes, we have it...
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_MSG_NOSIGNAL, 1, [use MSG_NOSIGNAL for send()])
], [
# We'll have to use signals
AC_MSG_RESULT(no)
])
dnl-----------------------------------------------------------------------------
dnl check for POSIX real-time scheduling
dnl-----------------------------------------------------------------------------
AC_CHECK_FUNCS( sched_getscheduler sched_getparam )
dnl-----------------------------------------------------------------------------
dnl enable compilation with debug flags
dnl-----------------------------------------------------------------------------
AC_SUBST(DEBUG_CXXFLAGS)
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug], [enable debug mode @<:@no@:>@]),
[], enable_debug=no)
AS_IF([test "x$enable_debug" = xyes],
[DEBUG_CXXFLAGS="-g"
AC_MSG_RESULT([compiling in debug mode])],
AC_MSG_RESULT([not compiling in debug mode]))
AC_OUTPUT(Makefile src/Makefile man/Makefile)

View File

@ -0,0 +1,84 @@
# sample DarkIce configuration file, edit for your needs before using
# see the darkice.cfg man page for details
# this section describes general aspects of the live streaming session
[general]
duration = 60 # duration of encoding, in seconds. 0 means forever
bufferSecs = 5 # size of internal slip buffer, in seconds
reconnect = yes # reconnect to the server(s) if disconnected
realtime = yes # run the encoder with POSIX realtime priority
rtprio = 3 # scheduling priority for the realtime threads
# this section describes the audio input that will be streamed
[input]
device = /dev/dsp # OSS DSP soundcard device for the audio input
sampleRate = 22050 # sample rate in Hz. try 11025, 22050 or 44100
bitsPerSample = 16 # bits per sample. try 16
channel = 2 # channels. 1 = mono, 2 = stereo
# this section describes a streaming connection to an IceCast2 server
# there may be up to 8 of these sections, named [icecast2-0] ... [icecast2-7]
# these can be mixed with [icecast-x] and [shoutcast-x] sections
[icecast2-0]
bitrateMode = abr # average bit rate
format = vorbis # format of the stream: ogg vorbis
bitrate = 96 # bitrate of the stream sent to the server
server = yp.yourserver.com
# host name of the server
port = 8000 # port of the IceCast2 server, usually 8000
password = hackme # source password to the IceCast2 server
mountPoint = sample96 # mount point of this stream on the IceCast2 server
name = DarkIce trial
# name of the stream
description = This is only a trial
# description of the stream
url = http://www.yourserver.com
# URL related to the stream
genre = my own # genre of the stream
public = yes # advertise this stream?
localDumpFile = dump.ogg # local dump file
# this section describes a streaming connection to an IceCast server
# there may be up to 8 of these sections, named [icecast-0] ... [icecast-7]
# these can be mixed with [icecast2-x] and [shoutcast-x] sections
[icecast-0]
bitrateMode = cbr # constant bit rate
bitrate = 96 # bitrate of the mp3 stream sent to the server
quality = 0.8 # encoding quality
server = yp.yourserver.com
# host name of the server
port = 8000 # port of the IceCast server, usually 8000
password = hackme # source password to the IceCast server
mountPoint = sample96 # mount point of this stream on the IceCast server
name = DarkIce trial
# name of the stream
description = This is only a trial
# description of the stream
url = http://www.yourserver.com
# URL related to the stream
genre = my own # genre of the stream
public = yes # advertise this stream?
# this section describes a streaming connection to a ShoutCast server
# there may be up to 8 of these sections, named [shoutcast-0] ... [shoutcast-7]
# these can be mixed with [icecast-x] and [icecast2-x] sections
[shoutcast-0]
bitrateMode = vbr # variable bit rate mode
quality = 0.5 # encoding quality
server = yp.yourserver.com
# host name of the server
port = 8001 # source port of the ShoutCast server, usually 8001
password = hackme # source password to the ShoutCast server
name = DarkIce trial
# name of the stream
url = http://www.yourserver.com
# URL related to the stream
genre = my own # genre of the stream
public = yes # advertise this stream?
irc = irc.yourserver.com
# IRC info related to the stream
aim = aim here # AIM info related to the stream
icq = I see you too
# ICQ info related to the stream

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
IUSE="encode oggvorbis alsa jack"
DESCRIPTION="IceCast live streamer delivering Ogg and mp3 streams simultaneously to multiple hosts."
HOMEPAGE="http://darkice.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.gz"
RESTRICT="nomirror"
SLOT="0"
LICENSE="GPL-2"
KEYWORDS="~x86 ~ppc ~sparc ~alpha ~hppa ~amd64"
DEPEND="encode? ( >=media-sound/lame-3.89 )
oggvorbis? ( >=media-libs/libvorbis-1.0 )
alsa? ( >=media-libs/alsa-lib-1.0.0 )
jack? ( media-sound/jack-audio-connection-kit )"
src_compile() {
if ! use encode && ! use oggvorbis
then
eerror "You need support for mp3 or Ogg Vorbis enconding for this"
eerror "package. Please merge again with at least one of the "
eerror "\`encode' and \`oggvorbis' USE flags enabled:"
eerror
eerror " # USE=\"encode\" emerge darkice"
eerror " # USE=\"oggvorbis\" emerge darkice"
die "Won't build without support for lame nor vorbis"
fi
econf `use_with alsa` \
`use_with encode lame` \
`use_with oggvorbis vorbis` \
`use_with jack` || die
emake || die "Compilation failed"
}
src_install() {
einstall darkicedocdir=${D}/usr/share/doc/${PF} || die
dodoc AUTHORS ChangeLog COPYING NEWS README TODO
}

View File

@ -0,0 +1,45 @@
IUSE="encode oggvorbis aac alsa jack"
DESCRIPTION="IceCast live streamer delivering Ogg, mp3 or aac streams simultaneously to multiple hosts."
HOMEPAGE="http://darkice.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.gz"
RESTRICT="nomirror"
SLOT="0"
LICENSE="GPL-2"
KEYWORDS="~x86 ~ppc ~sparc ~alpha ~hppa ~amd64"
DEPEND="encode? ( >=media-sound/lame-3.89 )
oggvorbis? ( >=media-libs/libvorbis-1.0 )
aac? ( >=media-libs/faac-1.24 )
alsa? ( >=media-libs/alsa-lib-1.0.0 )
jack? ( media-sound/jack-audio-connection-kit )"
src_compile() {
if ! use encode && ! use oggvorbis && ! use aac
then
eerror "You need support for mp3, Ogg Vorbis or FAAC enconding for this"
eerror "package. Please merge again with at least one of the "
eerror "\`encode', \`oggvorbis' or \'aac' USE flags enabled:"
eerror
eerror " # USE=\"encode\" emerge darkice"
eerror " # USE=\"oggvorbis\" emerge darkice"
eerror " # USE=\"aac\" emerge darkice"
die "Won't build without support for lame, vorbis or aac"
fi
econf `use_with alsa` \
`use_with encode lame` \
`use_with oggvorbis vorbis` \
`use_with aac faac` \
`use_with jack` || die
emake || die "Compilation failed"
}
src_install() {
einstall darkicedocdir=${D}/usr/share/doc/${PF} || die
dodoc AUTHORS ChangeLog COPYING NEWS README TODO
}

View File

@ -0,0 +1,43 @@
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header$
DESCRIPTION="IceCast live streamer, delivering ogg and mp3 streams simultaneously to multiple hosts."
HOMEPAGE="http://darkice.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.gz"
LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~alpha ~amd64 ~hppa ~ppc ~sparc ~x86"
IUSE="alsa encode jack vorbis"
DEPEND="encode? ( >=media-sound/lame-1.89 )
vorbis? ( >=media-libs/libvorbis-1.0 )
alsa? ( >=media-libs/alsa-lib-1.0.0 )
jack? ( media-sound/jack-audio-connection-kit )"
src_compile() {
if ! use encode && ! use vorbis
then
eerror "You need support for mp3 or Ogg Vorbis enconding for this"
eerror "package. Please merge again with at least one of the "
eerror "\`encode' and \`vorbis' USE flags enabled:"
eerror
eerror " # USE=\"encode\" emerge darkice"
eerror " # USE=\"vorbis\" emerge darkice"
die "Won't build without support for lame nor vorbis"
fi
econf $(use_with alsa) \
$(use_with encode lame) \
$(use_with jack) \
$(use_with vorbis) || die "configuration failed"
emake || die "Compilation failed"
}
src_install() {
einstall darkicedocdir=${D}/usr/share/doc/${PF} || die "make install failed"
dodoc AUTHORS ChangeLog NEWS README TODO
}

View File

@ -0,0 +1,48 @@
IUSE="encode mp2 oggvorbis aac alsa jack"
DESCRIPTION="IceCast live streamer delivering Ogg, mp3, mp2 or aac streams simultaneously to multiple hosts."
HOMEPAGE="http://darkice.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.gz"
RESTRICT="nomirror"
SLOT="0"
LICENSE="GPL-2"
KEYWORDS="~x86 ~ppc ~sparc ~alpha ~hppa ~amd64"
DEPEND="encode? ( >=media-sound/lame-3.89 )
mp2? ( >=media-sound/twolame-0.3.6 )
oggvorbis? ( >=media-libs/libvorbis-1.0 )
aac? ( >=media-libs/faac-1.24 )
alsa? ( >=media-libs/alsa-lib-1.0.0 )
jack? ( media-sound/jack-audio-connection-kit )"
src_compile() {
if ! use encode && ! use mp2 && ! use oggvorbis && ! use aac
then
eerror "You need support for mp3, Ogg Vorbis or FAAC enconding for this"
eerror "package. Please merge again with at least one of the "
eerror "\`encode', \'mp2', \`oggvorbis' or \'aac' USE flags enabled:"
eerror
eerror " # USE=\"encode\" emerge darkice"
eerror " # USE=\"mp2\" emerge darkice"
eerror " # USE=\"oggvorbis\" emerge darkice"
eerror " # USE=\"aac\" emerge darkice"
die "Won't build without support for lame, mp2, vorbis or aac"
fi
econf `use_with alsa` \
`use_with encode lame` \
`use_with mp2 twolame` \
`use_with oggvorbis vorbis` \
`use_with aac faac` \
`use_with jack` || die
emake || die "Compilation failed"
}
src_install() {
einstall darkicedocdir=${D}/usr/share/doc/${PF} || die
dodoc AUTHORS ChangeLog COPYING NEWS README TODO
}

View File

@ -0,0 +1,43 @@
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header$
DESCRIPTION="IceCast live streamer, delivering ogg and mp3 streams simultaneously to multiple hosts."
HOMEPAGE="http://darkice.tyrell.hu/"
SRC_URI="http://darkice.tyrell.hu/dist/${PV}/${P}.tar.gz"
LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~alpha ~amd64 ~hppa ~ppc ~sparc ~x86"
IUSE="alsa encode jack vorbis"
DEPEND="encode? ( >=media-sound/lame-1.89 )
vorbis? ( >=media-libs/libvorbis-1.0 )
alsa? ( >=media-libs/alsa-lib-1.0.0 )
jack? ( media-sound/jack-audio-connection-kit )"
src_compile() {
if ! use encode && ! use vorbis
then
eerror "You need support for mp3 or Ogg Vorbis enconding for this"
eerror "package. Please merge again with at least one of the "
eerror "\`encode' and \`vorbis' USE flags enabled:"
eerror
eerror " # USE=\"encode\" emerge darkice"
eerror " # USE=\"vorbis\" emerge darkice"
die "Won't build without support for lame nor vorbis"
fi
econf $(use_with alsa) \
$(use_with encode lame) \
$(use_with jack) \
$(use_with vorbis) || die "configuration failed"
emake || die "Compilation failed"
}
src_install() {
einstall darkicedocdir=${D}/usr/share/doc/${PF} || die "make install failed"
dodoc AUTHORS ChangeLog NEWS README TODO
}

View File

@ -0,0 +1,43 @@
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header$
DESCRIPTION="IceCast live streamer, delivering ogg and mp3 streams simultaneously to multiple hosts."
HOMEPAGE="http://darkice.tyrell.hu/"
SRC_URI="http://darkice.tyrell.hu/dist/${PV}/${P}.tar.gz"
LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~alpha ~amd64 ~hppa ~ppc ~sparc ~x86"
IUSE="alsa encode jack vorbis"
DEPEND="encode? ( >=media-sound/lame-1.89 )
vorbis? ( >=media-libs/libvorbis-1.0 )
alsa? ( >=media-libs/alsa-lib-1.0.0 )
jack? ( media-sound/jack-audio-connection-kit )"
src_compile() {
if ! use encode && ! use vorbis
then
eerror "You need support for mp3 or Ogg Vorbis enconding for this"
eerror "package. Please merge again with at least one of the "
eerror "\`encode' and \`vorbis' USE flags enabled:"
eerror
eerror " # USE=\"encode\" emerge darkice"
eerror " # USE=\"vorbis\" emerge darkice"
die "Won't build without support for lame nor vorbis"
fi
econf $(use_with alsa) \
$(use_with encode lame) \
$(use_with jack) \
$(use_with vorbis) || die "configuration failed"
emake || die "Compilation failed"
}
src_install() {
einstall darkicedocdir=${D}/usr/share/doc/${PF} || die "make install failed"
dodoc AUTHORS ChangeLog NEWS README TODO
}

View File

@ -0,0 +1,43 @@
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header$
DESCRIPTION="IceCast live streamer, delivering ogg and mp3 streams simultaneously to multiple hosts."
HOMEPAGE="http://darkice.tyrell.hu/"
SRC_URI="http://darkice.tyrell.hu/dist/${PV}/${P}.tar.gz"
LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~alpha ~amd64 ~hppa ~ppc ~sparc ~x86"
IUSE="alsa encode jack vorbis"
DEPEND="encode? ( >=media-sound/lame-1.89 )
vorbis? ( >=media-libs/libvorbis-1.0 )
alsa? ( >=media-libs/alsa-lib-1.0.0 )
jack? ( media-sound/jack-audio-connection-kit )"
src_compile() {
if ! use encode && ! use vorbis
then
eerror "You need support for mp3 or Ogg Vorbis enconding for this"
eerror "package. Please merge again with at least one of the "
eerror "\`encode' and \`vorbis' USE flags enabled:"
eerror
eerror " # USE=\"encode\" emerge darkice"
eerror " # USE=\"vorbis\" emerge darkice"
die "Won't build without support for lame nor vorbis"
fi
econf $(use_with alsa) \
$(use_with encode lame) \
$(use_with jack) \
$(use_with vorbis) || die "configuration failed"
emake || die "Compilation failed"
}
src_install() {
einstall darkicedocdir=${D}/usr/share/doc/${PF} || die "make install failed"
dodoc AUTHORS ChangeLog NEWS README TODO
}

View File

@ -0,0 +1,21 @@
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header$
IUSE=""
DESCRIPTION="TwoLAME is an optimised MPEG Audio Layer 2 (MP2) encoder"
HOMEPAGE="http://www.twolame.org/"
SRC_URI="mirror://sourceforge/${PN}/${P}.tar.gz"
RESTRICT="nomirror"
SLOT="0"
LICENSE="GPL-2"
KEYWORDS="~x86 ~ppc ~sparc ~alpha ~hppa ~amd64"
DEPEND=">=media-libs/libsndfile-1.0.11"
src_install() {
make DESTDIR=${D} || die
dodoc AUTHORS ChangeLog COPYING README TODO
}

View File

@ -0,0 +1,60 @@
%{!?dist: %define dist fc3}
Summary : DarkIce live IceCast / ShoutCast streamer
Name: darkice
Vendor: Tyrell Hungary
Packager: Akos Maroy <darkeye@tyrell.hu>
Version: 0.18
Release: 1.%{dist}
Copyright: GPL
Group: Applications/Multimedia
Source: http://prdownloads.sourceforge.net/darkice/darkice-%{version}.tar.gz
URL: http://darkice.sourceforge.net/
Provides: darkice
BuildRoot: %{_tmppath}/%{name}-%{version}-root
BuildPrereq: lame-devel libogg-devel libvorbis-devel
%if %{dist} != el3
BuildPrereq: jack-audio-connection-kit-devel
%endif
Prefix: /usr
%description
DarkIce is an IceCast, IceCast2 and ShoutCast live audio streamer. It
takes audio input from a sound card, encodes it into mp3 and/or Ogg Vorbis,
and sends the mp3 stream to one or more IceCast and/or ShoutCast servers,
the Ogg Vorbis stream to one or more IceCast2 servers.
%prep
%setup
%build
%configure \
%if %{dist} == el3
--without-alsa --without-jack
%endif
make all
%install
rm -fr %{buildroot}
%makeinstall
%clean
rm -rf %{buildroot}
%files
%defattr (-, root, root)
%doc COPYING ChangeLog README TODO AUTHORS
%config(noreplace) %{_sysconfdir}/darkice.cfg
%{_bindir}/darkice
%{_mandir}/man1/darkice.1*
%{_mandir}/man5/darkice.cfg.5*
%changelog
* Thu May 18 2006 Akos Maroy <darkeye@tyrell.hu> 0.18-1
- rewrite the spec file for 0.18
* Tue Apr 19 2005 Akos Maroy <darkeye@tyrell.hu> 0.16-1
- rewrite the spec file for 0.16
* Tue Apr 19 2005 Akos Maroy <darkeye@tyrell.hu> 0.15-1
- rewrite the spec file for 0.15

View File

@ -0,0 +1,151 @@
#-------------------------------------------------------------------------------
#
# Copyright (c) 2000 Tyrell Corporation. All rights reserved.
#
# Tyrell DarkIce
#
# File : lame.spec
# Version : $Revision$
# Author : $Author$
# Location : $Source$
#
# Abstract :
#
# Specification file to build RPM packages of lame.
# Builds a proper lame executable on a RedHat 7.1 system.
# Based on the official lame RPM spec file by
# cefiar <cefiar1@optushome.com.au>
#
# Copyright notice:
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#-------------------------------------------------------------------------------
# ================================================================= local macros
%define name lame
%define ver 3.91
%define rel 1
%define prefix /usr
# ===================================================================== preamble
Summary : LAME Ain't an MP3 Encoder
Name: %{name}
Version: %{ver}
Release: %{rel}
Copyright: LGPL
Vendor: The LAME Project
Packager: Akos Maroy <darkeye@tyrell.hu>
URL: http://www.mp3dev.org/mp3/
Group: Applications/Multimedia
Source: http://prdownloads.sourceforge.net/darkice/%{name}-%{ver}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{ver}-root
Prefix: %{prefix}
Provides: lame
%description
LAME is an educational tool to be used for learning about MP3 encoding. The
goal of the LAME project is to use the open source model to improve the
psycho acoustics, noise shaping and speed of MP3. Another goal of the LAME
project is to use these improvements for the basis of a patent free audio
compression codec for the GNU project.
This build is optimized for %{_target}.
# ============================================================ devel sub-package
%package devel
Summary: Shared and static libraries for LAME.
Group: Development/Libraries
Requires: %{name} = %{version}
%description devel
LAME is an educational tool to be used for learning about MP3 encoding.
This package contains both the shared and the static libraries from the
LAME project.
You will also need to install the main lame package in order to install
these libraries.
This build is optimized for %{_target}.
# =================================================================== prep stage
%prep
%setup -n %{name}-%{ver}
# ================================================================== build stage
%build
export CC=gcc3
export CFLAGS="-O9"
%configure --with-fileio=lame \
--without-vorbis \
--disable-gtktest \
--enable-nasm \
--enable-expopt=full
make
# ================================================================ install stage
%install
%makeinstall
# ======================================================================== clean
%clean
rm -rf $RPM_BUILD_ROOT
make clean
# =========================================================== main package files
%files
%defattr (-,root,root)
%doc LICENSE USAGE COPYING TODO README*
%doc doc/html
%{_bindir}/lame
%{_mandir}/man1/lame.1*
%{_libdir}/libmp3lame.so.*
# ====================================================== devel sub-package files
%files devel
%defattr (-,root,root)
%doc API HACKING STYLEGUIDE
%{_includedir}/lame/lame.h
%{_libdir}/libmp3lame.la
%{_libdir}/libmp3lame.a
%{_libdir}/libmp3lame.so
# =================================================================== change log
#
# $Log$
# Revision 1.1 2005/04/14 11:58:08 darkeye
# moved directory rpm to etc/rpm
#
# Revision 1.4 2002/02/19 14:52:41 darkeye
# updated for lame 3.91
#
# Revision 1.3 2001/09/13 05:06:41 darkeye
# removed references to SourceForget FTP sites, as they are phased out
#
# Revision 1.2 2001/09/09 09:06:26 darkeye
# lame RPM is now created with gcc3 and full optimizations
#
# Revision 1.1 2001/09/02 12:46:05 darkeye
# added RPM package creation scripts
#
#

View File

@ -0,0 +1,4 @@
man_MANS = darkice.1 darkice.cfg.5
EXTRA_DIST = ${man_MANS}

View File

@ -0,0 +1,160 @@
.TH darkice 1 "November 20, 2007" "DarkIce" "DarkIce live audio streamer"
.SH NAME
darkice \- an icecast / shoutcast live audio streamer
.SH SYNOPSIS
.B darkice
[options] -c config.file
.SH DESCRIPTION
.PP
DarkIce as a live audio streamer. It records audio from an audio interface (e.g. sound card), encodes it and sends it to a streaming server.
DarkIce can record from:
* OSS audio devices
* ALSA audio devices
* Solaris audio interface
* Jack sources
* PulseAudio sources
DarkIce can encode in the following formats:
* mp3 - using the lame library
* mp2 - using the twolame library
* Ogg Vorbis
* Ogg Opus
* AAC - using the faac library
* AAC HEv2 - using the libaacplus (3GPP reference code)
DarkIce can send the encoded stream to the following streaming servers:
* ShoutCast
* IceCast 1.3.x and 2.x
* Darwin Streaming Server
Darkice runs on the following operating systems:
* FreeBSD
* Linux on intel and PowerPC
* MacOS X
* NetBSD / OpenBSD
* SUN Solaris
.B DarkIce
uses
.SM POSIX
real-time scheduling to keep up with sound card input.
.SM POSIX
real-time scheduling is only available if the program is run as root.
Therefore it is recommended that
.B DarkIce
is run as root.
.SH OPTIONS
.TP
.BI "\-c " config.file
Specifies what configuration file to use.
If not specified, /etc/darkice.cfg will be used.
.TP
.BI "\-v " n
Sets the verbosity level, between 0 and 10. 0 is silent, 10 is loud.
Defaults to 1.
.TP
.BI "\-h "
Prints the help page and exits.
.SH BUGS
.PP
Lots of bugs.
.SH "SEE ALSO"
darkice.cfg(5)
.SH AUTHOR
Akos Maroy
.I <darkeye@tyrell.hu>
.SH ACKNOWLEDGEMENTS
Developed with contributions by
Jim Crilly, <JCrilly@MSA.com>
aNa|0Gue, <analogue@glop.org>
Robin P. Blanchard, <Robin_Blanchard@gactr.uga.edu>
Tom Gray, <tomg@future-i.com>
Michael Smith, <msmith@labyrinth.net.au>
Julius O. Smith, <jos@ccrma.stanford.edu>
the OSALP team, http://osalp.sourceforge.net
Kristjan G. Bjarnason <kgb@gangverk.is>
Nicu Pavel <npavel@ituner.com>
Kai Krakow <kai@kaishome.de>
Atsuhiko Yamanaka <ymnk@jcraft.com>
Ricardo Galli <gallir@uib.es>
John Hay <jhay@icomtek.csir.co.za>
Christian Forster <forster@like.e-technik.uni-erlangen.de>
John Deeny <taqueso@dilapidated.org>
Robert Lunnon <bobl@optushome.com.au>
Enrico Ardizzoni <craken@users.sourceforge.net>
Deti Fliegl <deti@fliegl.de>
Nicholas J. Humfrey <njh@ecs.soton.ac.uk>
Joel Ebel <jbebel@ncsu.edu>
<jochen2@users.sourceforge.net>
Alexander Vlasov <zulu@galaradio.com>
Mariusz Mazur <mmazur@kernel.pl>
dsk <derrick@csociety.org>
Clyde Stubbs <clyde@htsoft.com>
Jens Maurer <Jens.Maurer@gmx.net>
Elod Horvath <elod@itfais.com>
Pierre Souchay <pierre@souchay.net>
Daniel Hazelbaker <daniel@highdesertchurch.com>
Alessandro Beretta <alessandro.baretta@radiomaria.org>
Roland Hermans <roland.hermans@omroepvenray.nl>
Rafael Diniz <rafael@riseup.net>
.SH LINKS
Project homepage:
.I http://code.google.com/p/darkice/
.B IceCast
homepage:
.I http://www.icecast.org/
.B ShoutCast
homepage:
.I http://www.shoutcast.com/
.B Darwin Streaming Server
homepage:
.I http://developer.apple.com/darwin/projects/streaming/
.B Lame
homepage:
.I http://www.mp3dev.org/mp3/
.B TwoLame
homepage:
.I http://www.twolame.org/
.B Ogg Vorbis
homepage:
.I http://www.xiph.org/ogg/vorbis/
.B Ogg Opus
homepage
.I http://www.opus-codec.org/
.B faac
homepage:
.I http://www.audiocoding.com/
.B libaacplus
homepage:
.I http://tipok.org.ua/node/17
.B DarkSnow
GTK front-end:
.I http://darksnow.radiolivre.org/index.en.html
written by Rafael Diniz

View File

@ -0,0 +1,688 @@
.TH darkice.cfg 5 "February 25, 2007" "DarkIce" "DarkIce live audio streamer"
.SH NAME
darkice.cfg \- configuration file for darkice
.SH DESCRIPTION
.PP
The configuration file consists of sections, with key = value pairs
separated with spaces and/or tabs inside each secion:
.nf
[section1]
# this is a whole line comment
key = value
an ugly key name = long value # this end is a comment too
[section2]
# this is a whole line comment in section 2
key = value
an ugly key name = long value # this end is a comment too
.fi
A proper
.B DarkIce
configuration file contains the following sections:
.nf
[general]
[input]
[icecast-0] ... [icecast-7]
[icecast2-0] ... [icecast2-7]
[shoutcast-0] ... [shoutcast-7]
[file-0] ... [file-7]
.fi
The order of the sections is not important. Sections [general] and [input]
are required, and at least one of [icecast-x], [icecast2-x], [shoutcast-x]
or [file-x] is needed.
In particular, the following sections and values are recognized:
.PP
.B [general]
This section describes general operational parameters (required).
Required values:
.TP
.I duration
Time for DarkIce to run, in seconds. If 0, run forever.
.TP
.I bufferSecs
Data read from the sound card is buffered before sent to
the encoder. Each buffer will be able to hold this
many seconds of samples.
.PP
Optional values:
.TP
.I reconnect
Try to reconnect to the server(s) if the connection is broken during
streaming, "yes" or "no". (optional parameter, defaults to "yes")
.TP
.I realtime
Use POSIX realtime scheduling, "yes" or "no".
(optional parameter, defaults to "yes")
.TP
.I rtprio
Scheduling priority for the realtime threads.
(optional parameter, defaults to 4)
.PP
.B [input]
This section describes the input (required).
Required values:
.TP
.I device
Specify the device to record from, which can be an OSS DSP device,
an ALSA source, PulseAudio source or you can use Jack audio.
- OSS DSP audio device to record from (e.g. /dev/dsp)
- ALSA DSP device name (e.g. hwplug:0,0)
- for PulseAudio use "pulseaudio"
- the string 'jack', to have an unconnected Jack port, or
'jack_auto' to automatically make Jack connect to the first source.
.TP
.I sampleRate
The sample rate to record with, samples per second
(e.g. 44100 for 44.1kHz CD-quality audio, 22050 for 22kHz or 11025
for 11kHz)
.TP
.I bitsPerSample
Number of bits to use for each sample (e.g. 8 bits or 16 bits)
.TP
.I channel
Number of channels to record (e.g. 1 for mono, 2 for stereo)
.TP
.I jackClientName
The name of the jack input channel created by darkice if device=jack
is specified.
.TP
.I paSourceName
The name of the PulseAudio source to use. It can be "default", an index or a device string obtained from running "pactl list"
.PP
.B [icecast-x]
This section describes an output to an
.B IceCast 1.3.x
server or
.B Darwin Streaming Server
, while encoding
with a lame encoder. There may be at most 8 outputs, numbered from 0 ... 7.
The number is included in the section name (e.g. [icecast-0] ... [icecast-7]).
The stream will be reachable at
.I http://<server>:<port>/<mountPoint>
Required values:
.TP
.I bitrateMode
The bit rate mode of the encoding, either "cbr", "abr" or "vbr",
standing for constant bit rate, average bit rate and variable bit
respectively. Use the bitrate and/or quality values to specify details
of the appropriate bit rate mode.
.TP
.I bitrate
Bit rate to encode to in kBits / sec (e.g. 96). Only used when cbr or
abr bit rate modes are specified.
.TP
.I quality
The quality of encoding a value between 0.0 .. 1.0 (e.g. 0.8), with 1.0 being
the highest quality. Use a value greater than 0.0. Only used when cbr or vbr
bit rate modes are specified.
.TP
.I server
The
.B IceCast
server's name (e.g. yp.yourserver.com)
.TP
.I port
The port to connect to the IceCast server (e.g. 8000)
.TP
.I password
The password to use to connect to the
.B IceCast
server
.TP
.I mountPoint
Mount point for the stream on the server
.PP
Optional values:
.TP
.I sampleRate
The sample rate of the encoded mp3 output. If not specified, defaults
to the value of the input sample rate.
.TP
.I channel
Number of channels for the mp3 output (e.g. 1 for mono, 2 for stereo).
If not specified, defaults to the value of the input sample rate.
.TP
.I name
Name of the stream
.TP
.I description
Description of the stream
.TP
.I url
Url related to the stream
.TP
.I genre
Genre of the stream
.TP
.I public
"yes" or "no", whether the stream is public
.TP
.I remoteDumpFile
The file the
.B IceCast
server should dump the contents of
this stream on its side.
.TP
.I localDumpFile
Dump the same mp3 data sent to the
.B IceCast
server to this local file.
.TP
.I fileAddDate
"yes" or "no" if you want to automatically insert a date string in
the localDumpFile name before its extension or at the end of file name if
no extension present
.TP
.I fileDateFormat
The date format to use for appending the date to the dump file name.
Defaults to "[%m-%d-%Y-%H-%M-%S]". All format strings acceptable by strftime()
can be used, see the strftime man page for details. Only applicable is
fileAddDate is "true".
.TP
.I lowpass
Lowpass filter setting for the lame encoder, in Hz. Frequencies above
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
.TP
.I highpass
Highpass filter setting for the lame encoder, in Hz. Frequencies below
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
.PP
.B [icecast2-x]
This section describes an output to an
.B IceCast2
server, while encoding with the ogg vobis encoder.
There may be at most 8 outputs, numbered from 0 ... 7.
The number is included in the section name (e.g. [icecast2-0] ... [icecast2-7]).
The stream will be reachable at
.I http://<server>:<port>/<mountPoint>
.P
.B DarkIce
supports both fixed bitrate and variable bitrate vorbis streams. When
using fixed bitrate, specify the bitrate using the
.I bitrate
field. When using variable bitrate, specify the quality of the stream by the
.I quality
field, which is a value between 0.0 and 1.0.
Required values:
.TP
.I format
Format of the stream sent to the
.B IceCast2
server. Supported formats are 'vorbis', 'opus', 'mp3', 'mp2', 'aac' and 'aacp'.
.TP
.I bitrateMode
The bit rate mode of the encoding, either "cbr", "abr" or "vbr",
standing for constant bit rate, average bit rate and variable bit
respectively. Use the bitrate and/or quality values to specify details
of the appropriate bit rate mode. Ogg Opus only supports 'cbr' and 'abr'.
.TP
.I bitrate
Bit rate to encode to in kBits / sec (e.g. 96). Only used when cbr or
abr bit rate modes are specified.
.TP
.I quality
The quality of encoding a value between 0.0 .. 1.0 (e.g. 0.8), with 1.0 being
the highest quality. Use a value greater than 0.0. Only used when vbr
bit rate mode is specified for Ogg Vorbis format, or in vbr and abr
modes for mp3 and mp2 format.
.TP
.I server
The
.B IceCast2
server's name (e.g. yp.yourserver.com)
.TP
.I port
The port to connect to the IceCast server (e.g. 8000)
.TP
.I password
The password to use to connect to the
.B IceCast2
server
.TP
.I mountPoint
Mount point for the stream on the server
.PP
Optional values:
.TP
.I sampleRate
The sample rate of the encoded output. If not specified, defaults
to the value of the input sample rate. Please note that Ogg Opus
only supports 48kHz sample rate, and will resample to this rate.
.TP
.I channel
Number of channels for the output (e.g. 1 for mono, 2 for stereo).
If not specified, defaults to the value of the input sample rate.
Different channels for input and output are only supported for mp3,
but not for Ogg Vorbis.
.TP
.I maxBitrate
The maximum bitrate of the stream. Only used when in cbr mode and in
Ogg Vorbis format.
.TP
.I name
Name of the stream
.TP
.I description
Description of the stream
.TP
.I url
Url related to the stream
.TP
.I genre
Genre of the stream
.TP
.I public
"yes" or "no", whether the stream is public
.TP
.I localDumpFile
Dump the same Ogg Vorbis data sent to the
.B IceCast2
server to this local file.
.TP
.I fileAddDate
"yes" or "no" if you want to automatically insert a date string in
the localDumpFile name before its extension or at the end of file name if
no extension present
.TP
.I fileDateFormat
The date format to use for appending the date to the dump file name.
Defaults to "[%m-%d-%Y-%H-%M-%S]". All format strings acceptable by strftime()
can be used, see the strftime man page for details. Only applicable is
fileAddDate is "true".
.TP
.I lowpass
Lowpass filter setting for the lame encoder, in Hz. Frequencies above
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
Only has effect if the mp3 or mp2 format is used.
.TP
.I highpass
Highpass filter setting for the lame encoder, in Hz. Frequencies below
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
Only has effect if the mp3 or mp2 format is used.
.PP
.B [shoutcast-x]
This section describes an output to a
.B ShoutCast
server, while encoding
with a lame encoder. There may be at most 8 outputs, numbered from 0 ... 7.
The number is included in the section name
(e.g. [shoutcast-0] ... [shoutcast-7]).
The stream will be reachable at
.I http://<server>:<port-1>/
Required values:
.TP
.I bitrateMode
The bit rate mode of the encoding, either "cbr", "abr" or "vbr",
standing for constant bit rate, average bit rate and variable bit
respectively. Use the bitrate and/or quality values to specify details
of the appropriate bit rate mode.
.TP
.I bitrate
Bit rate to encode to in kBits / sec (e.g. 96). Only used when cbr or
abr bit rate modes are specified.
.TP
.I quality
The quality of encoding a value between 0.0 .. 1.0 (e.g. 0.8), with 1.0 being
the highest quality. Use a value greater than 0.0. Only used when cbr or vbr
bit rate modes are specified.
.TP
.I server
The
.B ShoutCast
server's name (e.g. yp.yourserver.com)
.TP
.I port
The source port to connect to the ShoutCast server (e.g. 8001)
.TP
.I password
The password to use to connect to the
.B ShoutCast
server
.PP
Optional values:
.TP
.I mountPoint
Mount point for the stream on the server. Only works on Darwin Streaming
Server, the original Shoutcast server does not support mount points
.TP
.I sampleRate
The sample rate of the encoded mp3 output. If not specified, defaults
to the value of the input sample rate.
.TP
.I channel
Number of channels for the mp3 output (e.g. 1 for mono, 2 for stereo).
If not specified, defaults to the value of the input sample rate.
.TP
.I name
Name of the stream
.TP
.I url
Url related to the stream
.TP
.I genre
Genre of the stream
.TP
.I public
"yes" or "no", whether the stream is public
.TP
.I irc
IRC information related to the stream
.TP
.I aim
AIM information related to the stream
.TP
.I icq
ICQ information related to the stream
.TP
.I lowpass
Lowpass filter setting for the lame encoder, in Hz. Frequencies above
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
.TP
.I highpass
Highpass filter setting for the lame encoder, in Hz. Frequencies below
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
.TP
.I localDumpFile
Dump the same mp3 data sent to the
.B ShoutCast
server to this local file.
.TP
.I fileAddDate
"yes" or "no" if you want to automatically insert a date string in
the localDumpFile name before its extension or at the end of file name if
no extension present
.TP
.I fileDateFormat
The date format to use for appending the date to the dump file name.
Defaults to "[%m-%d-%Y-%H-%M-%S]". All format strings acceptable by strftime()
can be used, see the strftime man page for details. Only applicable is
fileAddDate is "true".
.PP
.B [file-x]
This section describes an output to a local file in either Ogg Vorbis or
mp3 format.
There may be at most 8 outputs, numbered from 0 ... 7.
The number is included in the section name (e.g. [file-0] ... [file-7]).
Required values:
.TP
.I format
Format to encode in. Must be either 'mp3', 'mp2', 'vorbis', 'opus', 'aac'
or 'aacp'.
.TP
.I bitrateMode
The bit rate mode of the encoding, either "cbr", "abr" or "vbr",
standing for constant bit rate, average bit rate and variable bit
respectively. Use the bitrate and/or quality values to specify details
of the appropriate bit rate mode.
.TP
.I bitrate
Bit rate to encode to in kBits / sec (e.g. 96). Only used when cbr or
abr bit rate modes are specified.
.TP
.I quality
The quality of encoding a value between 0.0 .. 1.0 (e.g. 0.8), with 1.0 being
the highest quality. Use a value greater than 0.0. Only used when cbr or vbr
bit rate modes are specified.
.TP
.I fileName
The name of the local file to save the encoded data into.
.PP
Optional values:
.TP
.I sampleRate
The sample rate of the encoded mp3 output. If not specified, defaults
to the value of the input sample rate.
Only used if the output format is mp3.
.TP
.I lowpass
Lowpass filter setting for the lame encoder, in Hz. Frequencies above
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
Only used if the output format is mp3.
.TP
.I highpass
Highpass filter setting for the lame encoder, in Hz. Frequencies below
the specified value will be cut.
If not set or set to 0, the encoder's default behaviour is used.
If set to -1, the filter is disabled.
Only used if the output format is mp3.
.PP
A sample configuration file follows. This file makes
.B DarkIce
stream for 1 minute (60 seconds) from the audio device
.I /dev/dsp
at 22.05kHz, 16 bit stereo.
It will build up a connection to the
.B IceCast
server yp.yourserver.com on port 8000 with the password "hackme".
The stream will be encoded to 96 kb/s mp3 with quality 0.8, and will be
reachable at
.I http://yp.yourserver.com:8000/live96
to mp3 players.
The encoding session will be stored by
.B IceCast
in the file
.I /tmp/server-dump.mp3
on the server side, and also by
.B DarkIce
in the file
.I /tmp/encoder-dump.mp3
on the encoder side.
.nf
[general]
duration = 60
bufferSecs = 5
[input]
device = /dev/dsp
sampleRate = 22050
bitsPerSample = 16
channel = 2
[icecast-0]
bitrateMode = cbr
bitrate = 96
quality = 0.8
server = yp.yourserver.com
port = 8000
password = hackme
mountPoint = live96
name = DarkIce trial
description = This is only a trial
url = http://www.yourserver.com
genre = live
public = no
remoteDumpFile = /tmp/server-dump.mp3
localDumpFile = /tmp/encoder-dump.mp3
fileAddDate = no
.fi
.PP
The following sample configuration file simply encodes the 16 bit stereo
44.1 kHz sound card input into Ogg Vorbis at average bit rate 96 kb/s for 60
seconds, and saves it in the local file at /tmp/save.ogg.
.nf
[general]
duration = 60
bufferSecs = 5
[input]
device = /dev/dsp
sampleRate = 44100
bitsPerSample = 16
channel = 2
[file-0]
format = vorbis
bitrateMode = abr
bitrate = 96
fileName = /tmp/save.ogg
.fi
.PP
A bit more complicated sample follows. This one makes
.B DarkIce
stream for 1 hour (3600 seconds) from the audio device
.I /dev/dsp
at 44.1kHz, 16 bit stereo.
It will build up a connection to an
.B IceCast
server yp.your-ice-server.com on port 8000 with the password "ice-hackme".
The sound for this stream will be cut at 10500 Hz from above.
The stream will be encoded to average bit rate 96 kb/s mp3 and resampled to
22.05kHz and 1 channel (mono).
The stream will be reachable at
.I http://yp.your-ice-server.com:8000/live96
to mp3 players.
The encoding session will be stored by
.B IceCast
in the file
.I /tmp/live96.mp3
on the server side.
It will also connect to a
.I ShoutCast
server at yp.your-shout-server.com on port 8001 with the password "shout-hackme"
This stream will be encoded to constant bit rate 128 kb/s mp3 with quality
0.8, and will be reachable at
.I http://yp.your-shout-server.com:8000
to mp3 players.
.nf
[general]
duration = 3600
bufferSecs = 5
[input]
device = /dev/dsp
sampleRate = 22050
bitsPerSample = 16
channel = 2
[icecast-0]
sampleRate = 22050
channel = 1
bitrateMode = abr
bitrate = 96
lowpass = 10500
server = yp.your-ice-server.com
port = 8000
password = ice-hackme
mountPoint = live96
name = DarkIce trial
description = This is only a trial
url = http://www.yourserver.com
genre = live
public = yes
remoteDumpFile = /tmp/live96.mp3
[shoutcast-0]
bitrateMode = cbr
bitrate = 128
quality = 0.8
server = yp.your-shout-server.com
port = 8001
password = shout-hackme
name = DarkIce trial
url = http://www.yourserver.com
genre = live
public = yes
irc = irc.yourserver.com
aim = aim here
icq = I see you too
.fi
.SH BUGS
.PP
Lots of bugs.
.SH "SEE ALSO"
darkice(1)
.SH AUTHOR
Akos Maroy
.I <darkeye@tyrell.hu>
.SH LINKS
Project homepage:
.I http://code.google.com/p/darkice/
.B IceCast
homepage:
.I http://www.icecast.org/
.B ShoutCast
homepage:
.I http://www.shoutcast.com/
.B Lame
homepage:
.I http://www.mp3dev.org/mp3/
.B Ogg Vorbis
homepage:
.I http://www.xiph.org/ogg/vorbis/
.B Ogg Opus
homepage:
.I http://www.opus-codec.org/

View File

@ -0,0 +1,131 @@
#!/bin/sh
# generic init file for darkice
#
# Niels Dettenbach - nd@syndicat.com - 2009-11-05
# Last Change: 2010-12-21
#
# thanks to:
# - Roland Whitehead
# GPL (2009)
# 0.7
## settings ##
# check your paths!
program=/usr/bin/darkice
pidfile=/var/run/darkice.pid
configfile=/etc/darkice.cfg
logfile=/var/log/darkice.log
progname="darkice"
restart_delay=2
verbose="5"
## end of settings ##
RETVAL=0
if [ ! -f $configfile ]
then
echo "$progname: config file not found"
exit
fi
if [ ! -f $program ]
then
echo "$progname: programm file $program not found"
exit
fi
case $1 in
'start')
if [ -f $pidfile ]; then
PID=`cat $pidfile`
running=`ps --no-headers -o "%c" -p $PID`
if ( [ "$progname" == "$running" ] ); then
echo "$progname is still running"
else
echo "$progname seems crashed - PID ($PID) does not match the deamon"
echo "removing stale PID File $pidfile"
rm -f $pidfile
$0 start
exit $?
fi
exit 0
else
echo -n $"Starting $progname "
RETVAL=1
$program -v $verbose -c $configfile 2>%1 >> $logfile &
echo
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
echo $! > $pidfile
echo " started"
else
echo " not started"
echo $RETVAL
exit 0
fi
RETVAL=$?
fi
;;
'stop')
if [ -f $pidfile ]; then
echo -n $"Stop $progname "
PID=`cat $pidfile`
kill -s TERM $PID 2> /dev/null
echo
sleep $restart_delay
rm -f $pidfile
echo " stopped"
else
echo "$progname not running"
fi
RETVAL=$?
;;
'status')
if [ -f $pidfile ]; then
PID=`cat $pidfile`
running=`ps --no-headers -o "%c" -p $PID`
if ( [ "$progname" == "$running" ] ); then
echo "$progname IS running with PID `cat $pidfile`."
else
echo "$progname process is dead or stale PID File $pidfile"
exit 0
fi
else
echo "$progname is not running"
exit 0
fi
;;
'restart')
$0 stop
$0 start
RETVAL=$?
;;
'restartifdown')
if [ -f $pidfile ]; then
PID=`cat $pidfile`
running=`ps --no-headers -o "%c" -p $PID`
if ( [ "$progname" == "$running" ] ); then
echo "$progname IS running with PID `cat $pidfile` - no restart."
else
echo "$progname PID $PID seems dead - restart"
$0 stop
$0 start
RETVAL=$?
fi
else
echo "PID file $pidfile found - restart"
$0 stop
$0 start
RETVAL=$?
fi
;;
*)
echo "Usage: $0 {start|stop|restart|status|restartifdown} "
exit 1;
;;
esac
exit $RETVAL

View File

@ -0,0 +1,290 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Copyright (c) 2004
LS Informationstechnik (LIKE)
University of Erlangen Nuremberg
All rights reserved.
Tyrell DarkIce
File : AlsaDspSource.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "AudioSource.h"
// compile only if configured for ALSA
#ifdef SUPPORT_ALSA_DSP
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "Util.h"
#include "Exception.h"
#include "AlsaDspSource.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Tell if source id big endian
*----------------------------------------------------------------------------*/
bool
AlsaDspSource :: isBigEndian ( void ) const throw ()
{
return SND_PCM_FORMAT_S16 == SND_PCM_FORMAT_S16_BE;
}
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
AlsaDspSource :: init ( const char * name ) throw ( Exception )
{
pcmName = Util::strDup( name);
captureHandle = 0;
bufferTime = 1000000; // Do 1s buffering
running = false;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
AlsaDspSource :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
delete[] pcmName;
}
/*------------------------------------------------------------------------------
* Open the audio source
*----------------------------------------------------------------------------*/
bool
AlsaDspSource :: open ( void ) throw ( Exception )
{
unsigned int u;
snd_pcm_format_t format;
snd_pcm_hw_params_t *hwParams;
if ( isOpen() ) {
return false;
}
switch ( getBitsPerSample() ) {
case 8:
format = SND_PCM_FORMAT_S8;
break;
case 16:
format = SND_PCM_FORMAT_S16;
break;
default:
return false;
}
if (snd_pcm_open(&captureHandle, pcmName, SND_PCM_STREAM_CAPTURE, 0) < 0) {
captureHandle = 0;
return false;
}
if (snd_pcm_hw_params_malloc(&hwParams) < 0) {
close();
throw Exception( __FILE__, __LINE__, "can't alloc hardware "\
"parameter structure");
}
if (snd_pcm_hw_params_any(captureHandle, hwParams) < 0) {
snd_pcm_hw_params_free(hwParams);
close();
throw Exception( __FILE__, __LINE__, "can't initialize hardware "\
"parameter structure");
}
if (snd_pcm_hw_params_set_access(captureHandle, hwParams,
SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
snd_pcm_hw_params_free(hwParams);
close();
throw Exception( __FILE__, __LINE__, "can't set access type");
}
if (snd_pcm_hw_params_set_format(captureHandle, hwParams, format) < 0) {
snd_pcm_hw_params_free(hwParams);
close();
throw Exception( __FILE__, __LINE__, "can't set sample format");
}
u = getSampleRate();
if (snd_pcm_hw_params_set_rate_near(captureHandle, hwParams, &u, 0) < 0) {
snd_pcm_hw_params_free(hwParams);
close();
throw Exception( __FILE__, __LINE__, "can't set sample rate", u);
}
u = getChannel();
if (snd_pcm_hw_params_set_channels(captureHandle, hwParams, u) < 0) {
snd_pcm_hw_params_free(hwParams);
close();
throw Exception( __FILE__, __LINE__, "can't set channels", u);
}
u = 4;
if (snd_pcm_hw_params_set_periods_near(captureHandle, hwParams, &u, 0)
< 0) {
snd_pcm_hw_params_free(hwParams);
close();
throw Exception( __FILE__, __LINE__, "can't set interrupt frequency");
}
u = getBufferTime();
if (snd_pcm_hw_params_set_buffer_time_near(captureHandle, hwParams, &u, 0)
< 0) {
snd_pcm_hw_params_free(hwParams);
close();
throw Exception( __FILE__, __LINE__, "can't set buffer size");
}
if (snd_pcm_hw_params(captureHandle, hwParams) < 0) {
snd_pcm_hw_params_free(hwParams);
close();
throw Exception( __FILE__, __LINE__, "can't set hardware parameters");
}
snd_pcm_hw_params_free(hwParams);
if (snd_pcm_prepare(captureHandle) < 0) {
close();
throw Exception( __FILE__, __LINE__, "can't prepare audio interface "\
"for use");
}
bytesPerFrame = getChannel() * getBitsPerSample() / 8;
return true;
}
/*------------------------------------------------------------------------------
* Check whether read() would return anything
*----------------------------------------------------------------------------*/
bool
AlsaDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
if ( !isOpen() ) {
return false;
}
if ( !running ) {
snd_pcm_start(captureHandle);
running = true;
}
/*
* FIXME How to check for available frames? It
* seems like snd_pcm_wait stops working when
* it comes to ALSA plugins... :-(
*
* int milliDelay = sec * 1000 + usec/1000;
* return snd_pcm_wait(captureHandle, milliDelay)!=0;
*/
return true; // bad!!
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
AlsaDspSource :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
snd_pcm_sframes_t ret;
if ( !isOpen() ) {
return 0;
}
do {
ret = snd_pcm_readi(captureHandle, buf, len/bytesPerFrame);
// Check for buffer overrun
if (ret == -EPIPE) {
reportEvent(1, "AlsaDspSource :: Buffer overrun!");
snd_pcm_prepare(captureHandle);
ret = -EAGAIN;
}
} while (ret == -EAGAIN);
if ( ret < 0 ) {
throw Exception(__FILE__, __LINE__, snd_strerror(ret));
}
running = true;
return ret * bytesPerFrame;
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
AlsaDspSource :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
snd_pcm_close(captureHandle);
captureHandle = 0;
running = false;
}
#endif // HAVE_ALSA_LIB

View File

@ -0,0 +1,299 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Copyright (c) 2004
LS Informationstechnik (LIKE)
University of Erlangen Nuremberg
All rights reserved.
Tyrell DarkIce
File : AlsaDspSource.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef ALSA_SOURCE_H
#define ALSA_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "Reporter.h"
#include "AudioSource.h"
#ifdef HAVE_ALSA_LIB
#include <alsa/asoundlib.h>
#else
#error configure for ALSA
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on the ALSA sound system
*
* @author $Author$
* @version $Revision$
*/
class AlsaDspSource : public AudioSource, public virtual Reporter
{
private:
/**
* Name of the capture PCM stream.
*/
char *pcmName;
/**
* Handle to access PCM stream data.
*/
snd_pcm_t *captureHandle;
/**
* Stores number of bytes per frame. One frame
* contains all samples per time instance.
*/
int bytesPerFrame;
/**
* Is the stream running?
*/
bool running;
/**
* Number of useconds to do buffering in the audio device.
*/
unsigned int bufferTime;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
AlsaDspSource ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @param name the PCM to open.
* @exception Exception
*/
void
init ( const char * name ) throw ( Exception );
/**
* De-iitialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param name the PCM (e.g. "hwplug:0,0").
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channel number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
AlsaDspSource ( const char * name,
int sampleRate = 44100,
int bitsPerSample = 16,
int channel = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channel)
{
init( name);
}
/**
* Copy Constructor.
*
* @param ds the object to copy.
* @exception Exception
*/
inline
AlsaDspSource ( const AlsaDspSource & ds ) throw ( Exception )
: AudioSource( ds )
{
init( ds.pcmName);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~AlsaDspSource ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual AlsaDspSource &
operator= ( const AlsaDspSource & ds ) throw ( Exception )
{
if ( this != &ds ) {
strip();
AudioSource::operator=( ds);
init( ds.pcmName);
}
return *this;
}
/**
* Tell if the data from this source comes in big or little endian.
*
* @return true if the source is big endian, false otherwise
*/
virtual bool
isBigEndian ( void ) const throw ();
/**
* Open the AlsaDspSource.
* This does not put Alsa device into recording mode.
* To start getting samples, call either canRead() or read().
*
* @return true if opening was successful, false otherwise
* @exception Exception
*
* @see #canRead
* @see #read
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the AlsaDspSource is open.
*
* @return true if the AlsaDspSource is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return captureHandle != 0;
}
/**
* Check if the AlsaDspSource can be read from.
* Blocks until the specified time for data to be available.
* Puts the PCM into recording mode.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the AlsaDspSource is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the AlsaDspSource.
* Puts the PCM into recording mode.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the AlsaDspSource.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
/**
* Returns the buffer size in useconds.
*
* @return the number of useconds audio will be buffered in ALSA
*/
inline virtual unsigned int
getBufferTime( void ) const
{
return bufferTime;
}
/**
* Sets the number of useconds to buffer audio in ALSA
*
* @param time buffer time
*/
inline virtual void
setBufferTime( unsigned int time ) {
bufferTime = time;
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* ALSA_SOURCE_H */

View File

@ -0,0 +1,493 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : AudioEncoder.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef AUDIO_ENCODER_H
#define AUDIO_ENCODER_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Referable.h"
#include "Sink.h"
#include "AudioSource.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio encoder
*
* @author $Author$
* @version $Revision$
*/
class AudioEncoder : public Sink, public virtual Referable
{
public:
/**
* Type to specify bitrate mode. Possible values:
* - cbr - constant bitrate mode
* described by bitrate
* - abr - average bitrate mode
* described by an average bitrate and quality
* - vbr - variable bitrate mode
* described by quality
*/
enum BitrateMode { cbr, abr, vbr };
private:
/**
* The Sink to dump the encoded data to
*/
Ref<Sink> sink;
/**
* Sample rate of the input.
*/
unsigned int inSampleRate;
/**
* Number of bits per sample of the input.
*/
unsigned int inBitsPerSample;
/**
* Number of channels of the input.
*/
unsigned int inChannel;
/**
* Is the input big endian or little endian?
*/
bool inBigEndian;
/**
* The bitrate mode of the encoder
*/
BitrateMode outBitrateMode;
/**
* Bit rate of the output in kbits/sec, for fixed bitrate encodings.
*/
unsigned int outBitrate;
/**
* Quality of the output, for variable bitrate encodings.
*/
double outQuality;
/**
* Sample rate of the output.
*/
unsigned int outSampleRate;
/**
* Number of channels of the output.
*/
unsigned int outChannel;
/**
* Initialize the object.
*
* @param sink the sink to send encoded output to
* @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input.
* @param inBigEndian shows if the input is big or little endian.
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output.
* @param outSampleRate sample rate of the output.
* @param outChannel number of channels of the output.
* @exception Exception
*/
inline void
init ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample,
unsigned int inChannel,
bool inBigEndian,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate,
unsigned int outChannel ) throw ( Exception )
{
this->sink = sink;
this->inSampleRate = inSampleRate;
this->inBitsPerSample = inBitsPerSample;
this->inChannel = inChannel;
this->inBigEndian = inBigEndian;
this->outBitrateMode = outBitrateMode;
this->outBitrate = outBitrate;
this->outQuality = outQuality;
this->outSampleRate = outSampleRate;
this->outChannel = outChannel;
if ( outQuality < -0.1 || 1.0 < outQuality ) {
throw Exception( __FILE__, __LINE__, "invalid encoder quality");
}
}
/**
* De-iitialize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
}
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
AudioEncoder ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Constructor.
*
* @param sink the sink to send encoded output to
* @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input.
* @param inBigEndian shows if the input is big or little endian
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, inSampleRate is used.
* @param outChannel number of channels of the output.
* If 0, inChannel is used.
* @exception Exception
*/
inline
AudioEncoder ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample,
unsigned int inChannel,
bool inBigEndian,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0 )
throw ( Exception )
{
init ( sink,
inSampleRate,
inBitsPerSample,
inChannel,
inBigEndian,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate ? outSampleRate : inSampleRate,
outChannel ? outChannel : inChannel );
}
/**
* Constructor.
*
* @param sink the sink to send encoded output to
* @param as get input sample rate, bits per sample and channels
* from this AudioSource.
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, input sample rate is used.
* @param outChannel number of channels of the output.
* If 0, input channel is used.
* @exception Exception
*/
inline
AudioEncoder ( Sink * sink,
const AudioSource * as,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0 )
throw ( Exception)
{
init( sink,
as->getSampleRate(),
as->getBitsPerSample(),
as->getChannel(),
as->isBigEndian(),
outBitrateMode,
outBitrate,
outQuality,
outSampleRate ? outSampleRate : as->getSampleRate(),
outChannel ? outChannel : as->getChannel() );
}
/**
* Copy constructor.
*
* @param encoder the AudioEncoder to copy.
*/
inline
AudioEncoder ( const AudioEncoder & encoder ) throw ( Exception )
{
init ( encoder.sink.get(),
encoder.inSampleRate,
encoder.inBitsPerSample,
encoder.inChannel,
encoder.inBigEndian,
encoder.outBitrateMode,
encoder.outBitrate,
encoder.outQuality,
encoder.outSampleRate,
encoder.outChannel );
}
/**
* Assignment operator.
*
* @param encoder the AudioEncoder to assign this to.
* @return a reference to this AudioEncoder.
* @exception Exception
*/
inline virtual AudioEncoder &
operator= ( const AudioEncoder & encoder ) throw ( Exception )
{
if ( this != &encoder ) {
strip();
init ( encoder.sink.get(),
encoder.inSampleRate,
encoder.inBitsPerSample,
encoder.inChannel,
encoder.inBigEndian,
encoder.outBitrateMode,
encoder.outBitrate,
encoder.outQuality,
encoder.outSampleRate,
encoder.outChannel );
}
return *this;
}
public:
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~AudioEncoder ( void ) throw ( Exception )
{
strip();
}
/**
* Get the underlying sink, that the encoded content is sent to.
*
* @return the underlying sink
*/
inline virtual Ref<Sink>
getSink(void) throw ()
{
return sink;
}
/**
* Get the number of channels of the input.
*
* @return the number of channels of the input.
*/
inline int
getInChannel ( void ) const throw ()
{
return inChannel;
}
/**
* Tell if the input is big or little endian.
*
* @return true if the input is big endian, false if little endian.
*/
inline bool
isInBigEndian ( void ) const throw ()
{
return inBigEndian;
}
/**
* Get the sample rate of the input.
*
* @return the sample rate of the input.
*/
inline int
getInSampleRate ( void ) const throw ()
{
return inSampleRate;
}
/**
* Get the number of bits per sample of the input.
*
* @return the number of bits per sample of the input.
*/
inline int
getInBitsPerSample ( void ) const throw ()
{
return inBitsPerSample;
}
/**
* Get the number of channels of the output.
*
* @return the number of channels of the output.
*/
inline int
getOutChannel ( void ) const throw ()
{
return outChannel;
}
/**
* Get the sample rate of the output.
*
* @return the sample rate of the output.
*/
inline int
getOutSampleRate ( void ) const throw ()
{
return outSampleRate;
}
/**
* Get the bit rate mode of the output.
*
* @return the bit rate mode of the output.
*/
inline BitrateMode
getOutBitrateMode ( void ) const throw ()
{
return outBitrateMode;
}
/**
* Get the bit rate of the output in kbits/sec, for fixed bitrate
* encodings.
*
* @return the bit rate of the output.
*/
inline unsigned int
getOutBitrate ( void ) const throw ()
{
return outBitrate;
}
/**
* Get the encoding quality of the output, for variable bitrate
* encodings.
*
* @return the encoding quality of the output.
*/
inline double
getOutQuality ( void ) const throw ()
{
return outQuality;
}
/**
* Check whether encoding is in progress.
*
* @return true if encoding is in progress, false otherwise.
*/
virtual bool
isRunning ( void ) const throw () = 0;
/**
* Start encoding. This function returns as soon as possible,
* with encoding started in the background.
*
* @return true if encoding has started, false otherwise.
* @exception Exception
*/
virtual bool
start ( void ) throw ( Exception ) = 0;
/**
* Stop encoding. Stops the encoding running in the background.
*
* @exception Exception
*/
virtual void
stop ( void ) throw ( Exception ) = 0;
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*
* Typically this action is delegated to the underlying sink.
*/
inline virtual void
cut ( void ) throw ()
{
sink->cut();
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* AUDIO_ENCODER_H */

View File

@ -0,0 +1,141 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : AudioSource.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "AudioSource.h"
#include "Util.h"
#include "Exception.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Return an audio source based on the compiled DSP supports and the
* supplied device name parameter.
*----------------------------------------------------------------------------*/
AudioSource *
AudioSource :: createDspSource( const char * deviceName,
const char * jackClientName,
const char * paSourceName,
int sampleRate,
int bitsPerSample,
int channel)
throw ( Exception )
{
if ( Util::strEq( deviceName, "/dev/tty", 8) ) {
#if defined( SUPPORT_SERIAL_ULAW )
Reporter::reportEvent( 1, "Using Serial Ulaw input device:",
deviceName);
return new SerialUlaw( deviceName,
sampleRate,
bitsPerSample,
channel);
#else
throw Exception( __FILE__, __LINE__,
"trying to open Serial ULaw device "
"without support compiled", deviceName);
#endif
} else if ( Util::strEq( deviceName, "/dev", 4) ) {
#if defined( SUPPORT_OSS_DSP )
Reporter::reportEvent( 1, "Using OSS DSP input device:", deviceName);
return new OssDspSource( deviceName,
sampleRate,
bitsPerSample,
channel);
#elif defined( SUPPORT_SOLARIS_DSP )
Reporter::reportEvent( 1, "Using Solaris DSP input device:",deviceName);
return new SolarisDspSource( deviceName,
sampleRate,
bitsPerSample,
channel);
#else
throw Exception( __FILE__, __LINE__,
"trying to open OSS or Solaris DSP device "
"without support compiled", deviceName);
#endif
} else if ( Util::strEq( deviceName, "jack", 4) ) {
#if defined( SUPPORT_JACK_DSP )
Reporter::reportEvent( 1, "Using JACK audio server as input device.");
return new JackDspSource( deviceName,
jackClientName,
sampleRate,
bitsPerSample,
channel);
#else
throw Exception( __FILE__, __LINE__,
"trying to open JACK device without "
"support compiled", deviceName);
#endif
} else if ( Util::strEq( deviceName, "pulseaudio", 10) ) {
#if defined( SUPPORT_PULSEAUDIO_DSP )
Reporter::reportEvent( 1, "Using PulseAudio audio server as input device.");
return new PulseAudioDspSource( paSourceName,
sampleRate,
bitsPerSample,
channel);
#else
throw Exception( __FILE__, __LINE__,
"trying to open PulseAudio device without "
"support compiled", deviceName);
#endif
} else {
#if defined( SUPPORT_ALSA_DSP )
Reporter::reportEvent( 1, "Using ALSA DSP input device:", deviceName);
return new AlsaDspSource( deviceName,
sampleRate,
bitsPerSample,
channel);
#else
throw Exception( __FILE__, __LINE__,
"trying to open ALSA DSP device without "
"support compiled", deviceName);
#endif
}
}

View File

@ -0,0 +1,338 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : AudioSource.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef AUDIO_SOURCE_H
#define AUDIO_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* ============================================================ include files */
#include "Source.h"
#include "Reporter.h"
/* ================================================================ constants */
/* =================================================================== macros */
/*------------------------------------------------------------------------------
* Determine the kind of audio device based on the system
*----------------------------------------------------------------------------*/
#if defined( HAVE_ALSA_LIB )
// we have an ALSA sound system available
#define SUPPORT_ALSA_DSP 1
#endif
#if defined( HAVE_PULSEAUDIO_LIB )
// we have an PULSEAUDIO sound system available
#define SUPPORT_PULSEAUDIO_DSP 1
#endif
#if defined( HAVE_SYS_SOUNDCARD_H )
// we have an OSS DSP sound source device available
#define SUPPORT_OSS_DSP 1
#endif
#if defined( HAVE_SYS_AUDIO_H ) || defined( HAVE_SYS_AUDIOIO_H )
// we have a Solaris DSP sound device available (same for OpenBSD)
#define SUPPORT_SOLARIS_DSP 1
#endif
#if defined( HAVE_JACK_LIB )
// we have JACK audio server
#define SUPPORT_JACK_DSP 1
#endif
#if defined ( HAVE_TERMIOS_H )
#define SUPPORT_SERIAL_ULAW 1
#endif
#if !defined( SUPPORT_ALSA_DSP ) \
&& !defined( SUPPORT_PULSEAUDIO_DSP ) \
&& !defined( SUPPORT_OSS_DSP ) \
&& !defined( SUPPORT_JACK_DSP ) \
&& !defined( SUPPORT_SOLARIS_DSP ) \
&& !defined( SUPPORT_SERIAL_ULAW)
// there was no DSP audio system found
#error No DSP audio input device found on system
#endif
/* =============================================================== data types */
/**
* Audio data input
*
* @author $Author$
* @version $Revision$
*/
class AudioSource : public Source, public virtual Reporter
{
private:
/**
* Number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.)
*/
unsigned int channel;
/**
* Samples per second (e.g. 44100 for 44.1kHz CD quality)
*/
unsigned int sampleRate;
/**
* Bits per sample (e.g. 8 bits, 16 bits, etc.)
*/
unsigned int bitsPerSample;
/**
* Initialize the object.
*
* @param sampleRate samples per second.
* @param bitsPerSample bits per sample.
* @param channel number of channels of the audio source.
* @exception Exception
*/
inline void
init ( unsigned int sampleRate,
unsigned int bitsPerSample,
unsigned int channel ) throw ( Exception )
{
this->sampleRate = sampleRate;
this->bitsPerSample = bitsPerSample;
this->channel = channel;
}
/**
* De-initialize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
}
protected:
/**
* Constructor.
* Because all values have defaults, this is also the default
* constructor.
*
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channel number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
AudioSource ( unsigned int sampleRate = 44100,
unsigned int bitsPerSample = 16,
unsigned int channel = 2 )
throw ( Exception )
{
init ( sampleRate, bitsPerSample, channel);
}
/**
* Copy Constructor.
*
* @param as the object to copy.
* @exception Exception
*/
inline
AudioSource ( const AudioSource & as ) throw ( Exception )
: Source( as )
{
init ( as.sampleRate, as.bitsPerSample, as.channel);
}
/**
* Assignment operator.
*
* @param as the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual AudioSource &
operator= ( const AudioSource & as ) throw ( Exception )
{
if ( this != &as ) {
strip();
Source::operator=( as );
init ( as.sampleRate, as.bitsPerSample, as.channel);
}
return *this;
}
public:
/**
* Destructor.
*
* @exception Exception
*/
virtual inline
~AudioSource ( void ) throw ( Exception )
{
}
/**
* Get the number of channels for this AudioSource.
*
* @return the number of channels.
*/
inline unsigned int
getChannel ( void ) const throw ()
{
return channel;
}
/**
* Tell if the data from this source comes in big or little endian.
*
* @return true if the data is big endian, false if little endian
*/
virtual bool
isBigEndian ( void ) const throw ()
{
#ifdef WORDS_BIGENDIAN
return true;
#else
return false;
#endif
}
/**
* Get the sample rate per seconds for this AudioSource.
*
* @return the sample rate per seconds.
*/
inline unsigned int
getSampleRate ( void ) const throw ()
{
return sampleRate;
}
/**
* Get the number of bits per sample for this AudioSource.
*
* @return the number of bits per sample.
*/
inline unsigned int
getBitsPerSample ( void ) const throw ()
{
return bitsPerSample;
}
/**
* Get the number of bytes for a sample for each channel
* (returns 4 bytes for 16 bits par sample in stereo)
*
* @return the number of bits per sample.
*/
inline unsigned int
getSampleSize ( void ) const throw ()
{
return bitsPerSample / 8 * channel;
}
/**
* Factory method for creating an AudioSource object of the
* appropriate type, based on the compiled DSP support and
* the supplied DSP name parameter.
*
* @param deviceName the audio device (/dev/dspX, hwplug:0,0, etc)
* @param jackClientName the source name for jack server
* @param paSourceName the pulse audio source
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channel number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
static AudioSource *
createDspSource( const char * deviceName,
const char * jackClientName,
const char * paSourceName,
int sampleRate = 44100,
int bitsPerSample = 16,
int channel = 2) throw ( Exception );
};
/* ================================================= external data structures */
/*------------------------------------------------------------------------------
* Determine the kind of audio device based on the system
*----------------------------------------------------------------------------*/
#if defined( SUPPORT_ALSA_DSP )
#include "AlsaDspSource.h"
#endif
#if defined( SUPPORT_PULSEAUDIO_DSP )
#include "PulseAudioDspSource.h"
#endif
#if defined( SUPPORT_OSS_DSP )
#include "OssDspSource.h"
#endif
#if defined( SUPPORT_SOLARIS_DSP )
#include "SolarisDspSource.h"
#endif
#if defined( SUPPORT_JACK_DSP )
#include "JackDspSource.h"
#endif
#if defined ( SUPPORT_SERIAL_ULAW )
#include "SerialUlaw.h"
#endif
/* ====================================================== function prototypes */
#endif /* AUDIO_SOURCE_H */

View File

@ -0,0 +1,434 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : BufferedSink.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
the buffer is filled like this:
buffer bufferEnd
| |
+----------+--------------------------+--------------+
|<---- valid data -------->|
outp inp
buffer bufferEnd
| |
+----------------+--------------+--------------------+
-- valid data -->| |--- valid data ----->
inp outp
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#include "Exception.h"
#include "BufferedSink.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
BufferedSink :: init ( Sink * sink,
unsigned int size,
unsigned int chunkSize ) throw ( Exception )
{
if ( !sink ) {
throw Exception( __FILE__, __LINE__, "no sink");
}
this->sink = sink; // create a reference
this->chunkSize = chunkSize ? chunkSize : 1;
this->bufferSize = size;
// make bufferSize a multiple of chunkSize
this->bufferSize -= this->bufferSize % this->chunkSize;
this->peak = 0;
this->misalignment = 0;
this->buffer = new unsigned char[bufferSize];
this->bufferEnd = buffer + bufferSize;
this->inp = buffer;
this->outp = buffer;
this->bOpen = true;
this->openAttempts = 0;
}
/*------------------------------------------------------------------------------
* Copy Constructor
*----------------------------------------------------------------------------*/
BufferedSink :: BufferedSink ( const BufferedSink & buffer )
throw ( Exception )
{
init( buffer.sink.get(), buffer.bufferSize, buffer.chunkSize);
this->peak = buffer.peak;
this->misalignment = buffer.misalignment;
this->bOpen = buffer.bOpen;
this->openAttempts = buffer.openAttempts;
memcpy( this->buffer, buffer.buffer, this->bufferSize);
}
/*------------------------------------------------------------------------------
* De-initalize the object
*----------------------------------------------------------------------------*/
void
BufferedSink :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
sink = 0; // delete the reference
delete buffer;
}
/*------------------------------------------------------------------------------
* Assignment operator
*----------------------------------------------------------------------------*/
BufferedSink &
BufferedSink :: operator= ( const BufferedSink & buffer )
throw ( Exception )
{
if ( this != &buffer ) {
strip();
Sink::operator=( buffer );
init( buffer.sink.get(), buffer.bufferSize, buffer.chunkSize);
this->peak = buffer.peak;
this->misalignment = buffer.misalignment;
this->bOpen = buffer.bOpen;
this->openAttempts = buffer.openAttempts;
memcpy( this->buffer, buffer.buffer, this->bufferSize);
}
return *this;
}
/*------------------------------------------------------------------------------
* Store bufferSize bytes into the buffer
* All data is consumed. The return value is less then bufferSize only
* if the BufferedSink's internal buffer is smaller than bufferSize,
* thus can't hold that much
* The data to be stored is treated as parts with chunkSize size
* Only full chunkSize sized parts are stored
*----------------------------------------------------------------------------*/
unsigned int
BufferedSink :: store ( const void * buffer,
unsigned int bufferSize ) throw ( Exception )
{
const unsigned char * buf;
unsigned int size;
unsigned int i;
unsigned char * oldInp;
if ( !buffer ) {
throw Exception( __FILE__, __LINE__, "buffer is null");
}
if ( !bufferSize ) {
return 0;
}
unsigned int remaining = this->bufferSize - ( outp <= inp ? inp - outp :
(bufferEnd - outp) + (inp - this->buffer) );
// react only to the first overrun whenever there is a series of overruns
if ( remaining + chunkSize <= bufferSize && remaining > chunkSize ) {
reportEvent(3,"BufferedSink :: store, buffer overrun");
throw Exception( __FILE__, __LINE__,
"buffer overrun");
}
oldInp = inp;
buf = (const unsigned char *) buffer;
// adjust so it is a multiple of chunkSize
bufferSize -= bufferSize % chunkSize;
// cut the front of the supplied buffer if it wouldn't fit
if ( bufferSize > this->bufferSize ) {
size = this->bufferSize - 1;
size -= size % chunkSize; // keep it a multiple of chunkSize
buf += bufferSize - size;
} else {
size = bufferSize;
}
// copy the data into the buffer
i = bufferEnd - inp;
if ( (i % chunkSize) != 0 ) {
throw Exception( __FILE__, __LINE__, "copy quantity not aligned", i);
}
if ( size <= i ) {
// the place between inp and bufferEnd is
// big enough to hold the data
memcpy( inp, buf, size);
inp = slidePointer( inp, size);
// adjust outp, lose the data that was overwritten, if any
if ( outp > oldInp && outp <= inp ) {
outp = slidePointer( inp, chunkSize);
}
} else {
// the place between inp and bufferEnd is not
// big enough to hold the data
// writing will take place in two turns, once from
// inp -> bufferEnd, then from buffer ->
memcpy( inp, buf, i);
i = size - i;
if ( (i % chunkSize) != 0 ) {
throw Exception(__FILE__, __LINE__, "copy quantity not aligned", i);
}
memcpy( this->buffer, buf, i);
inp = slidePointer( this->buffer, i);
// adjust outp, lose the data that was overwritten, if any
if ( outp <= oldInp ) {
if ( outp < inp ) {
outp = slidePointer( inp, chunkSize);
}
} else {
outp = slidePointer( inp, chunkSize);
}
}
updatePeak();
if ( ((inp - this->buffer) % chunkSize) != 0 ) {
throw Exception( __FILE__, __LINE__,
"inp not aligned", inp - this->buffer);
}
if ( ((outp - this->buffer) % chunkSize) != 0 ) {
throw Exception( __FILE__, __LINE__,
"outp not aligned", outp - this->buffer);
}
return size;
}
/*------------------------------------------------------------------------------
* Write some data to the sink
* if len == 0, try to flush the buffer
*----------------------------------------------------------------------------*/
unsigned int
BufferedSink :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
unsigned int length = 0;
unsigned int soFar = 0;
unsigned char * b = (unsigned char *) buf;
if ( !buf ) {
throw Exception( __FILE__, __LINE__, "buf is null");
}
if ( !isOpen() ) {
return 0;
}
if ( !align() ) {
return 0;
}
if ( !sink->isOpen() && openAttempts < 10 ) {
// try to reopen underlying sink, because it has closed on its own
openAttempts++;
try {
if( sink->open() ) {
// if reopening succeeds, reset open attempts
openAttempts = 0;
}
} catch ( Exception &e ) {
reportEvent( 4,"BufferedSink :: write,",
"couldn't reopen underlying sink, attempt",
openAttempts, "/ 10" );
}
if( openAttempts == 10 ) {
// all the attempts have been used, give up
close();
throw Exception( __FILE__, __LINE__,
"reopen failed");
}
}
// make it a multiple of chunkSize
len -= len % chunkSize;
// try to write data from the buffer first, if any
if ( inp != outp ) {
unsigned int size = 0;
unsigned int total = 0;
if ( outp > inp ) {
// valuable data is between outp -> bufferEnd and buffer -> inp
// try to write the outp -> bufferEnd
// the rest will be written in the next if
size = bufferEnd - outp;
size -= size % chunkSize;
if( size > len * 2 ) {
// do not try to send the content of the entire buffer at once,
// but limit sending to a multiple of len
// this prevents a surge of data to underlying buffer
// which is important especially during a lot of packet loss
size = len * 2;
}
soFar = 0;
while ( outp > inp && soFar < size && sink->canWrite( 0, 0) ) {
try {
length = sink->write( outp + soFar, size - soFar);
} catch (Exception &e) {
length = 0;
reportEvent(3,"Exception caught in BufferedSink :: write1");
}
outp = slidePointer( outp, length);
soFar += length;
}
total += soFar;
}
if ( outp < inp ) {
// valuable data is between outp and inp
// in the previous if wrote all data from the end
// this part will write the rest
size = inp - outp;
if( size > len * 2 ) {
// prevent a surge of data to underlying buffer
size = len * 2;
}
soFar = 0;
while ( soFar < size && sink->canWrite( 0, 0) ) {
try {
length = sink->write( outp + soFar, size - soFar);
} catch (Exception &e) {
length = 0;
reportEvent(3,"Exception caught in BufferedSink :: write2" );
}
outp = slidePointer( outp, length);
soFar += length;
}
total += soFar;
}
while ( (outp - buffer) % chunkSize ) {
slidePointer( outp, 1);
}
// calulate the misalignment to chunkSize boundaries
misalignment = (chunkSize - (total % chunkSize)) % chunkSize;
}
if ( !align() ) {
return 0;
}
// the internal buffer is empty, try to write the fresh data
soFar = 0;
if ( inp == outp ) {
while ( soFar < len && sink->canWrite( 0, 0) ) {
try {
soFar += sink->write( b + soFar, len - soFar);
} catch (Exception &e) {
reportEvent(3,"Exception caught in BufferedSink :: write3");
}
}
}
length = soFar;
// calulate the misalignment to chunkSize boundaries
misalignment = (chunkSize - (length % chunkSize)) % chunkSize;
if ( length < len ) {
// if not all fresh could be written, store the remains
store( b + length, len - length);
}
updatePeak();
// tell them we ate everything up to chunkSize alignment
return len;
}
/*------------------------------------------------------------------------------
* Close the sink, lose all pending data
*----------------------------------------------------------------------------*/
void
BufferedSink :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
flush();
sink->close();
inp = outp = buffer;
bOpen = false;
}

View File

@ -0,0 +1,419 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : BufferedSink.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef BUFFERED_SINK_H
#define BUFFERED_SINK_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Ref.h"
#include "Reporter.h"
#include "Sink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A Sink First-In First-Out buffer.
* This buffer can always be written to, it overwrites any
* data contained if needed.
* The class is not thread-safe.
*
* @author $Author$
* @version $Revision$
*/
class BufferedSink : public Sink, public virtual Reporter
{
private:
/**
* The buffer.
*/
unsigned char * buffer;
/**
* The end of the buffer.
*/
unsigned char * bufferEnd;
/**
* The size of the buffer.
*/
unsigned int bufferSize;
/**
* The highest usage of the buffer.
*/
unsigned int peak;
/**
* All data written to this BufferedSink is handled by chuncks
* of this size.
*/
unsigned int chunkSize;
/**
* Number of bytes the underlying stream is misaligned with
* chunkSize. (It needs this many bytes more to be aligned.)
*/
unsigned int misalignment;
/**
* Start of free territory in buffer.
*/
unsigned char * inp;
/**
* Start of sensible data in buffer.
*/
unsigned char * outp;
/**
* The underlying Sink.
*/
Ref<Sink> sink;
/**
* Is BufferedSink open.
*/
bool bOpen;
/**
* Number of attempts so far to open underlying sink after it has
* closed on its own.
*/
unsigned int openAttempts;
/**
* Initialize the object.
*
* @param sink the Sink to attach this BufferedSink to.
* @param size the size of the internal buffer to use.
* @param chunkSize size of chunks to handle data in.
* @exception Exception
*/
void
init ( Sink * sink,
unsigned int size,
unsigned int chunkSize ) throw ( Exception );
/**
* De-initialize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
/**
* Slide a pointer in the internal buffer by offset. If the pointer
* would reach beyond the end of the buffer, it goes wraps around.
*
* @param p the pointer to slide.
* @param offset the amount to slide with.
* @return pointer p + offset, wrapped around if needed.
*/
inline unsigned char *
slidePointer (
unsigned char * p,
unsigned int offset ) throw ()
{
p += offset;
while ( p >= bufferEnd ) {
p -= bufferSize;
}
return p;
}
/**
* Update the peak buffer usage indicator.
*
* @see #peak
*/
inline void
updatePeak ( void ) throw ()
{
unsigned int u;
u = outp <= inp ? inp - outp : (bufferEnd - outp) + (inp - buffer);
// report new peaks if it is either significantly more severe than
// the previously reported peak
if ( peak * 2 < u ) {
peak = u;
reportEvent( 4, "BufferedSink, new peak:", peak, " / ", bufferSize);
}
if ( peak > 0 && u == 0 ) {
peak = 0;
reportEvent( 4, "BufferedSink, healed:", peak, " / ", bufferSize);
}
}
/**
* If the underlying Sink is misaligned on chunkSize, write as
* many 0s as needed to get it aligned.
*
* @see #misalignment
* @see #chunkSize
*/
inline bool
align ( void ) throw ( Exception )
{
char b[] = { 0 };
while ( misalignment ) {
if ( sink->canWrite( 0, 0) ) {
unsigned int ret;
if ( !(ret = sink->write( b, 1)) ) {
return false;
}
--misalignment;
} else {
return false;
}
}
return true;
}
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
BufferedSink ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Get the size of the buffer.
*
* @return the size of the buffer.
*/
inline unsigned int
getSize ( void ) const throw ()
{
return bufferSize;
}
/**
* Store data in the internal buffer. If there is not enough space,
* discard all in the buffer and the beginning of the supplied
* buffer if needed.
*
* @param buffer the data to store.
* @param bufferSize the amount of data to store in bytes.
* @return number of bytes really stored.
*/
unsigned int
store ( const void * buffer,
unsigned int bufferSize ) throw ( Exception );
public:
/**
* Constructor by an underlying Sink, buffer size and chunk size.
*
* @param sink the Sink to attach this BufferSink to.
* @param size the size of the buffer to use for buffering.
* @param chunkSize hanlde all data in write() as chunks of
* chunkSize
* @exception Exception
*/
inline
BufferedSink ( Sink * sink,
unsigned int size,
unsigned int chunkSize = 1 ) throw ( Exception )
{
init( sink, size, chunkSize);
}
/**
* Copy constructor.
*
* @param buffer the object to copy.
* @exception Exception
*/
BufferedSink ( const BufferedSink & buffer ) throw ( Exception );
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~BufferedSink ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param bs the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
virtual BufferedSink &
operator= ( const BufferedSink & bs ) throw ( Exception );
/**
* Get the peak usage of the internal buffer.
*
* @return the peak usage of the internal buffer.
*/
inline unsigned int
getPeak ( void ) const throw ()
{
return peak;
}
/**
* Open the BufferedSink. Opens the underlying Sink.
*
* @return true if opening was successful, false otherwise.
* @exception Exception
*/
inline virtual bool
open ( void ) throw ( Exception )
{
bOpen = sink->open();
openAttempts = 0;
return bOpen;
}
/**
* Check if a BufferedSink is open.
*
* @return true if the BufferedSink is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return bOpen;
}
/**
* Check if the BufferedSink is ready to accept data.
* Always returns true immediately.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
return true;
}
/**
* Write data to the BufferedSink.
* Always reads the maximum number of chunkSize chunks buf
* holds. If the data can not be written to the underlying
* stream, it is buffered. If the buffer overflows, the oldest
* data is discarded.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* Flush all data that was written to the BufferedSink to the
* underlying Sink.
*
* @exception Exception
*/
inline virtual void
flush ( void ) throw ( Exception )
{
unsigned char b[1];
write( b, 0);
}
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
inline virtual void
cut ( void ) throw ()
{
flush();
sink->cut();
}
/**
* Close the BufferedSink. Closes the underlying Sink.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* BUFFERED_SINK_H */

View File

@ -0,0 +1,133 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : CastSink.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "Util.h"
#include "Exception.h"
#include "CastSink.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
CastSink :: init ( TcpSocket * socket,
Sink * streamDump,
const char * password,
unsigned int bitRate,
const char * name,
const char * url,
const char * genre,
bool isPublic )
throw ( Exception )
{
this->socket = socket;
this->streamDump = streamDump;
this->password = password ? Util::strDup( password) : 0;
this->bitRate = bitRate;
this->name = name ? Util::strDup( name) : 0;
this->url = url ? Util::strDup( url) : 0;
this->genre = genre ? Util::strDup( genre) : 0;
this->isPublic = isPublic;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
CastSink :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
if ( password ) {
delete[] password;
}
if ( name ) {
delete[] name;
}
if ( url ) {
delete[] url;
}
if ( genre ) {
delete[] genre;
}
}
/*------------------------------------------------------------------------------
* Open the connection
*----------------------------------------------------------------------------*/
bool
CastSink :: open ( void ) throw ( Exception )
{
if ( isOpen() ) {
return false;
}
if ( !getSink()->open() ) {
return false;
}
if ( !sendLogin() ) {
close();
return false;
}
if ( streamDump != 0 ) {
if ( !streamDump->isOpen() ) {
if ( !streamDump->open() ) {
reportEvent( 2, "can't open stream dump");
}
}
}
return true;
}

View File

@ -0,0 +1,454 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : CastSink.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef CAST_SINK_H
#define CAST_SINK_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Ref.h"
#include "Reporter.h"
#include "Sink.h"
#include "TcpSocket.h"
#include "BufferedSink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Data output to a ShoutCast / IceCast / etc. server
* This is an abstract class. A subclass should override at least
* the sendLogin() function.
*
* @author $Author$
* @version $Revision$
*/
class CastSink : public Sink, public virtual Reporter
{
private:
/**
* The socket connection to the server.
*/
Ref<TcpSocket> socket;
/**
* An optional Sink to enable stream dumps.
*/
Ref<Sink> streamDump;
/**
* Password to the server.
*/
char * password;
/**
* Name of the stream.
*/
char * name;
/**
* URL associated with the stream.
*/
char * url;
/**
* Genre of the stream.
*/
char * genre;
/**
* Bitrate of the stream (e.g. mp3 bitrate).
*/
unsigned int bitRate;
/**
* Is the stream public?
*/
bool isPublic;
/**
* Initalize the object.
*
* @param socket socket connection to the server.
* @param password password to the server.
* @param name name of the stream.
* @param url URL associated with the stream.
* @param genre genre of the stream.
* @param bitRate bitrate of the stream (e.g. mp3 bitrate).
* @param isPublic is the stream public?
* @exception Exception
*/
void
init ( TcpSocket * socket,
Sink * streamDump,
const char * password,
unsigned int bitRate,
const char * name,
const char * url,
const char * genre,
bool isPublic)
throw ( Exception );
/**
* De-initalize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
CastSink ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Log in to the server using the socket avialable.
*
* @return true if login was successful, false otherwise.
* @exception Exception
*/
virtual bool
sendLogin ( void ) throw ( Exception ) = 0;
/**
* Get the Sink underneath this CastSink.
*
* @return pointer to the Sink underneath this CastSink.
*/
inline Sink *
getSink ( void ) const throw ()
{
return getSocket();
}
/**
* Get the TcpSocket underneath this CastSink.
*
* @return pointer to the TcpSocket underneath this CastSink.
*/
inline TcpSocket *
getSocket ( void ) const throw ()
{
return socket.get();
}
public:
/**
* Constructor.
*
* @param socket socket connection to the server.
* @param password password to the server.
* @param name name of the stream.
* @param url URL associated with the stream.
* @param genre genre of the stream.
* @param bitRate bitrate of the stream (e.g. mp3 bitrate).
* @param isPublic is the stream public?
* @param streamDump a Sink to dump the streamed binary data to
*
* @exception Exception
*/
inline
CastSink ( TcpSocket * socket,
const char * password,
unsigned int bitRate,
const char * name = 0,
const char * url = 0,
const char * genre = 0,
bool isPublic = false,
Sink * streamDump = 0)
throw ( Exception )
{
init( socket,
streamDump,
password,
bitRate,
name,
url,
genre,
isPublic );
}
/**
* Copy constructor.
*
* @param cs the CastSink to copy.
*/
inline
CastSink( const CastSink & cs ) throw ( Exception )
: Sink( cs )
{
init( cs.socket.get(),
cs.streamDump.get(),
cs.password,
cs.bitRate,
cs.name,
cs.url,
cs.genre,
cs.isPublic );
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~CastSink( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param cs the CastSink to assign this to.
* @return a reference to this CastSink.
* @exception Exception
*/
inline virtual CastSink &
operator= ( const CastSink & cs ) throw ( Exception )
{
if ( this != &cs ) {
strip();
Sink::operator=( cs );
init( cs.socket.get(),
cs.streamDump.get(),
cs.password,
cs.bitRate,
cs.name,
cs.url,
cs.genre,
cs.isPublic );
}
return *this;
}
/**
* Open the CastSink.
* Logs in to the server.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the CastSink is open.
*
* @return true if the CastSink is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
if( !getSink() ) {
return false;
}
return getSink()->isOpen();
}
/**
* Check if the CastSink is ready to accept data.
* Blocks until the specified time for data to be available.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the CastSink is ready to accept data,
* false otherwise.
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
return getSink()->canWrite( sec, usec);
}
/**
* Write data to the CastSink.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
inline virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception )
{
if ( streamDump != 0 ) {
streamDump->write( buf, len);
}
return getSink()->write( buf, len);
}
/**
* Flush all data that was written to the CastSink to the server.
*
* @exception Exception
*/
inline virtual void
flush ( void ) throw ( Exception )
{
if ( streamDump != 0 ) {
streamDump->flush();
}
return getSink()->flush();
}
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
inline virtual void
cut ( void ) throw ()
{
if ( streamDump != 0 ) {
streamDump->cut();
}
}
/**
* Close the CastSink.
*
* @exception Exception
*/
inline virtual void
close ( void ) throw ( Exception )
{
if ( streamDump != 0 ) {
streamDump->close();
}
return getSink()->close();
}
/**
* Get the password to the server.
*
* @return the password to the server.
*/
inline const char *
getPassword ( void ) const throw ()
{
return password;
}
/**
* Get the name of the stream.
*
* @return the name of the stream.
*/
inline const char *
getName ( void ) const throw ()
{
return name;
}
/**
* Get the URL associated with the stream.
*
* @return the URL associated with the stream.
*/
inline const char *
getUrl ( void ) const throw ()
{
return url;
}
/**
* Get the genre of the stream.
*
* @return the genre of the stream.
*/
inline const char *
getGenre ( void ) const throw ()
{
return genre;
}
/**
* Get the bitrate of the stream (e.g. mp3 bitrate).
*
* @return the bitrate of the stream (e.g. mp3 bitrate).
*/
inline unsigned int
getBitRate ( void ) const throw ()
{
return bitRate;
}
/**
* Get whether this stream is public.
*
* @return true if the stream is public, false otherwise.
*/
inline bool
getIsPublic ( void ) const throw ()
{
return isPublic;
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* CAST_SINK_H */

View File

@ -0,0 +1,173 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell ConfigSection
File : ConfigSection.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <iterator>
#include <iostream>
#include "ConfigSection.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/*------------------------------------------------------------------------------
* string containing all white space characters
*----------------------------------------------------------------------------*/
#define WHITE_SPACE_STR " \t"
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Add a key / value pair
*----------------------------------------------------------------------------*/
bool
ConfigSection :: add ( const char * key,
const char * value ) throw ( Exception )
{
if ( !key || !value ) {
throw Exception( __FILE__, __LINE__, "no key or value");
}
std::pair<const std::string, std::string> element( key, value);
std::pair<TableType::iterator, bool> res;
res = table.insert( element);
return res.second;
}
/*------------------------------------------------------------------------------
* Get a value for a key
*----------------------------------------------------------------------------*/
const char *
ConfigSection :: get ( const char * key ) const throw ( Exception )
{
if ( !key ) {
throw Exception( __FILE__, __LINE__, "no key");
}
TableType::const_iterator it = table.find( key);
if ( it == table.end() ) {
return 0;
}
return it->second.c_str();
}
/*------------------------------------------------------------------------------
* Get a value for a key, in the key does not exist, throw an exception
*----------------------------------------------------------------------------*/
const char *
ConfigSection :: getForSure ( const char * key,
const char * message1,
const char * message2,
int code ) const
throw ( Exception )
{
const char * value;
if ( !(value = get( key)) ) {
throw Exception( __FILE__, __LINE__, key, message1, message2, code);
}
return value;
}
/*------------------------------------------------------------------------------
* Add a configuration line
*----------------------------------------------------------------------------*/
bool
ConfigSection :: addLine ( const char * line ) throw ( Exception )
{
if ( !line ) {
throw Exception( __FILE__, __LINE__, "no line");
}
std::string::size_type ix;
std::string str( line);
/* delete everything after the first # */
if ( (ix = str.find( '#')) != str.npos ) {
str.erase( ix);
}
/* eat up all white space from the front */
if ( (ix = str.find_first_not_of( WHITE_SPACE_STR)) != str.npos ) {
str.erase( 0, ix);
}
/* eat up all white space from the end */
if ( (ix = str.find_last_not_of( WHITE_SPACE_STR)) != str.npos ) {
str.erase( ix + 1);
}
if ( !str.length() ) {
return true;
}
/* find the '=' delimiter between key and value */
if ( (ix = str.find( '=')) == str.npos ) {
return false;
}
std::string key( str, 0, ix);
std::string value( str, ix + 1);
/* eat up all white space from the front of value */
if ( (ix = value.find_first_not_of( WHITE_SPACE_STR)) != value.npos ) {
value.erase( 0, ix);
}
/* eat up all white space from the end of key */
if ( (ix = key.find_last_not_of( WHITE_SPACE_STR)) != key.npos ) {
key.erase( ix + 1);
}
/* now add the new key / value pair */
return add( key.c_str(), value.c_str());
}

View File

@ -0,0 +1,184 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell ConfigSection
File : ConfigSection.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef CONFIG_SECTION_H
#define CONFIG_SECTION_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include <map>
#include <string>
#include "Referable.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A configuration file representation. The file is of the syntax:
*
* <pre>
* # this is a whole line comment
* key = value
* an ugly key name = long value # this end is a comment too
* </pre>
*
* also empty lines are ignored and all white space is removed
* from the front and end of keys / values
*
* Knwon problem: you can't use '#' in any part of a key / value pair
*
* @author $Author$
* @version $Revision$
*/
class ConfigSection : public virtual Referable
{
private:
/**
* Type of the hash table used in this class.
*/
typedef std::map<std::string, std::string> TableType;
/**
* Hash table holding the configuration information.
*/
TableType table;
protected:
public:
/**
* Default constructor.
*
* @exception Exception
*/
inline
ConfigSection ( void ) throw ( Exception )
{
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~ConfigSection ( void ) throw ( Exception )
{
}
/* TODO
inline
ConfigSection ( const ConfigSection & di ) throw ( Exception )
{
}
inline ConfigSection &
operator= ( const ConfigSection * di ) throw ( Exception )
{
}
*/
/**
* Add a key / value pair to the configuration information.
*
* @param key the key to add the value by
* @param value the value to add for the key
* @return true if adding was successful, false otherwise
* @exception Exception
*/
virtual bool
add ( const char * key,
const char * value ) throw ( Exception );
/**
* Get a value for a key.
*
* @param key the key to get the value for
* @return the value for the key, or NULL if the key doesn't exist.
* @exception Exception
*/
virtual const char *
get ( const char * key ) const throw ( Exception );
/**
* Get a value for a key, or throw an Exception.
*
* @param key the key to get the value for
* @param message1 message part 1 of the Exception to be thrown.
* @param message2 message part 2 of the Exception to be thrown.
* @param code error code of the Exception to be thrown.
* @return the value for the key. The return value is never NULL.
* @exception Exception
*/
virtual const char *
getForSure ( const char * key,
const char * message1 = 0,
const char * message2 = 0,
int code = 0 ) const
throw ( Exception );
/**
* Add a line of configuration information.
*
* @param line the line to add.
* @return true if a new key was added, false otherwise.
* @exception Exception
*/
virtual bool
addLine ( const char * line ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* CONFIG_SECTION_H */

View File

@ -0,0 +1,358 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Connector.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "Exception.h"
#include "Connector.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
Connector :: init ( Source * source ) throw ( Exception )
{
this->source = source;
this->sinks = 0;
this->numSinks = 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
Connector :: strip ( void ) throw ( Exception )
{
source = 0;
if ( sinks ) {
unsigned int u;
for ( u = 0; u < numSinks; ++u ) {
sinks[u] = 0;
}
delete[] sinks;
}
}
/*------------------------------------------------------------------------------
* Constructor
*----------------------------------------------------------------------------*/
Connector :: Connector ( const Connector & connector ) throw ( Exception )
{
unsigned int u;
init( connector.source.get());
for ( u = 0; u < connector.numSinks; ++u ) {
attach( connector.sinks[u].get() );
}
}
/*------------------------------------------------------------------------------
* Assignment operator
*----------------------------------------------------------------------------*/
Connector &
Connector :: operator= ( const Connector & connector ) throw ( Exception )
{
if ( this != &connector ) {
unsigned int u;
// first free everything
strip();
// then fill in
init( connector.source.get() );
for ( u = 0; u < connector.numSinks; ++u ) {
attach( connector.sinks[u].get() );
}
}
return *this;
}
/*------------------------------------------------------------------------------
* Attach a sink to the connector
*----------------------------------------------------------------------------*/
void
Connector :: attach ( Sink * sink ) throw ( Exception )
{
if ( !sinks ) {
numSinks = 1;
sinks = new Ref<Sink>[1];
sinks[0] = sink;
} else {
unsigned int u;
Ref<Sink> * s = new Ref<Sink>[numSinks + 1];
for ( u = 0; u < numSinks; ++u ) {
s[u] = sinks[u].get();
}
s[numSinks] = sink;
delete[] sinks;
sinks = s;
++numSinks;
}
}
/*------------------------------------------------------------------------------
* Detach a sink to the connector
*----------------------------------------------------------------------------*/
bool
Connector :: detach ( Sink * sink ) throw ( Exception )
{
if ( numSinks == 0 ) {
return false;
} else if ( numSinks == 1 ) {
if ( sinks[0].get() != sink ) {
return false;
}
sinks[0] = 0;
delete[] sinks;
sinks = 0;
--numSinks;
return true;
} else {
unsigned int u;
unsigned int v;
unsigned int ix;
Ref<Sink> * s;
ix = numSinks;
for ( u = 0; u < numSinks; ++u ) {
if ( sinks[u].get() == sink ) {
ix = u;
break;
}
}
if ( ix == numSinks ) {
return false;
}
s = new Ref<Sink>[numSinks - 1];
for ( u = 0, v = 0; u < numSinks; ++u ) {
if ( u != ix ) {
s[v++] = sinks[u];
}
}
sinks[ix] = 0;
delete[] sinks;
sinks = s;
--numSinks;
return true;
}
}
/*------------------------------------------------------------------------------
* Open the source and all the sinks if needed
*----------------------------------------------------------------------------*/
bool
Connector :: open ( void ) throw ( Exception )
{
unsigned int u;
if ( !source->isOpen() ) {
if ( !source->open() ) {
return false;
}
}
for ( u = 0; u < numSinks; ++u ) {
if ( !sinks[u]->isOpen() ) {
if ( !sinks[u]->open() ) {
break;
}
}
}
// if not all could be opened, close those that were
if ( u < numSinks ) {
unsigned int v;
for ( v = 0; v < u; ++v ) {
sinks[v]->close();
}
source->close();
return false;
}
return true;
}
/*------------------------------------------------------------------------------
* Transfer some data from the source to the sink
*----------------------------------------------------------------------------*/
unsigned int
Connector :: transfer ( unsigned long bytes,
unsigned int bufSize,
unsigned int sec,
unsigned int usec ) throw ( Exception )
{
unsigned int u;
unsigned long b;
if ( numSinks == 0 ) {
return 0;
}
if ( bufSize == 0 ) {
return 0;
}
unsigned char * buf = new unsigned char[bufSize];
reportEvent( 6, "Connector :: transfer, bytes", bytes);
for ( b = 0; !bytes || b < bytes; ) {
unsigned int d = 0;
unsigned int e = 0;
if ( source->canRead( sec, usec) ) {
d = source->read( buf, bufSize);
// check for EOF
if ( d == 0 ) {
reportEvent( 3, "Connector :: transfer, EOF");
break;
}
for ( u = 0; u < numSinks; ++u ) {
if ( sinks[u]->canWrite( sec, usec) ) {
try {
// we expect the sink to accept all data written
e = sinks[u]->write( buf, d);
} catch ( Exception & e ) {
sinks[u]->close();
detach( sinks[u].get() );
reportEvent( 4,
"Connector :: transfer, sink removed, remaining",
numSinks);
if ( numSinks == 0 ) {
reportEvent( 4,
"Connector :: transfer, no more sinks");
delete[] buf;
return b;
}
// with the call to detach, numSinks gets 1 lower,
// and the next sink comes to sinks[u]
--u;
}
}
}
b += d;
} else {
reportEvent( 3, "Connector :: transfer, can't read");
break;
}
}
delete[] buf;
return b;
}
/*------------------------------------------------------------------------------
* Signal to each sink to cut what they've done so far, and start anew.
*----------------------------------------------------------------------------*/
void
Connector :: cut ( void ) throw ()
{
unsigned int u;
for ( u = 0; u < numSinks; ++u ) {
if ( sinks[u]->isOpen() ) {
sinks[u]->cut();
}
}
}
/*------------------------------------------------------------------------------
* Close the source and all the sinks if needed
*----------------------------------------------------------------------------*/
void
Connector :: close ( void ) throw ( Exception )
{
unsigned int u;
source->close();
for ( u = 0; u < numSinks; ++u ) {
sinks[u]->close();
}
}

View File

@ -0,0 +1,264 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Connector.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef CONNECTOR_H
#define CONNECTOR_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Referable.h"
#include "Ref.h"
#include "Reporter.h"
#include "Source.h"
#include "Sink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Connects a source to one or more sinks.
*
* @author $Author$
* @version $Revision$
*/
class Connector : public virtual Referable, public virtual Reporter
{
private:
/**
* Initialize the object.
*
* @param source the source to read from.
* @exception Exception
*/
void
init ( Source * source ) throw ( Exception );
/**
* De-initialize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
protected:
/**
* The source to read from.
*/
Ref<Source> source;
/**
* The sinks to connect the source to.
*/
Ref<Sink> * sinks;
/**
* Total number of sinks.
*/
unsigned int numSinks;
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
Connector ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Detach an already attached Sink from the Source of this Connector.
*
* @param sink the Sink to detach.
* @return true if the detachment was successful, false otherwise.
* @exception Exception
*/
virtual bool
detach ( Sink * sink ) throw ( Exception );
public:
/**
* Constructor based on a Source.
*
* @param source the source to connect to the sinks.
* @exception Exception
*/
inline
Connector ( Source * source ) throw ( Exception )
{
init( source);
}
/**
* Constructor based on a Source and a Sink.
*
* @param source the source to connect to the sinks.
* @param sink a sink to connect to the source.
* @exception Exception
*/
inline
Connector ( Source * source,
Sink * sink ) throw ( Exception )
{
init( source);
attach( sink);
}
/**
* Copy constructor.
*
* @param connector the object to copy.
* @exception Exception
*/
Connector ( const Connector & connector ) throw ( Exception );
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~Connector( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param connector the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
virtual Connector &
operator= ( const Connector & connector ) throw ( Exception );
/**
* Get the number of Sinks in the Connector.
*
* @return the number of Sinks in the Connector.
* @exception Exception
*/
inline virtual unsigned int
getNumSinks ( void ) const throw ()
{
return numSinks;
}
/**
* Attach a Sink to the Source of this Connector.
*
* @param sink the Sink to attach.
* @exception Exception
*/
virtual void
attach ( Sink * sink ) throw ( Exception );
/**
* Open the connector. Opens the Source and the Sinks if necessary.
*
* @return true if opening was successful, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Transfer a given amount of data from the Source to all the
* Sinks attached.
* If an attached Sink closes or encounteres an error during the
* process, it is detached and the function carries on with the
* rest of the Sinks. If no Sinks remain, or an error is encountered
* with the Source, the function returns prematurely.
*
* @param bytes the amount of data to transfer, in bytes.
* If 0, transfer forever.
* @param bufSize the size of the buffer to use for transfering.
* This amount of data is read from the Source and
* written to each Sink on each turn.
* @param sec the number of seconds to wait for the Source to have
* data available in each turn, and the number of seconds
* to wait for the Sinks to accept data.
* @param usec the number of micro seconds to wait for the Source to
* have data available in each turn, and the number of
* micro seconds to wait for the Sinks to accept data.
* @return the number of bytes read from the Source.
* @exception Exception
*/
virtual unsigned int
transfer ( unsigned long bytes,
unsigned int bufSize,
unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Signal to each sink we have that they need to cut what they are
* doing, and start again. For FileSinks, this usually means to
* save the archive file recorded so far, and start a new archive
* file.
*/
virtual void
cut ( void ) throw ();
/**
* Close the Connector. The Source and all Sinks are closed.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* CONNECTOR_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,324 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : DarkIce.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef DARK_ICE_H
#define DARK_ICE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#include <iostream>
#include "Referable.h"
#include "Reporter.h"
#include "Exception.h"
#include "Ref.h"
#include "AudioSource.h"
#include "BufferedSink.h"
#include "Connector.h"
#include "AudioEncoder.h"
#include "TcpSocket.h"
#include "CastSink.h"
#include "DarkIceConfig.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Program main object.
*
* @author $Author$
* @version $Revision$
*/
class DarkIce : public virtual Referable, public virtual Reporter
{
private:
/**
* The maximum number of supported outputs. This should be
* <supported output types> * <outputs per type>
*/
static const unsigned int maxOutput = 4 * 7;
/**
* Type describing each lame library output.
*/
typedef struct {
Ref<Sink> encoder;
Ref<TcpSocket> socket;
Ref<CastSink> server;
} Output;
/**
* The outputs.
*/
Output audioOuts[maxOutput];
/**
* Number of lame library outputs.
*/
unsigned int noAudioOuts;
/**
* Duration of playing, in seconds.
*/
unsigned int duration;
/**
* The dsp to record from.
*/
Ref<AudioSource> dsp;
/**
* The encoding Connector, connecting the dsp to the encoders.
*/
Ref<Connector> encConnector;
/**
* Should we turn real-time scheduling on ?
*/
int enableRealTime;
/**
* Scheduling priority for the realtime threads
*/
int realTimeSchedPriority;
/**
* Original scheduling policy
*/
int origSchedPolicy;
/**
* Original scheduling priority
*/
int origSchedPriority;
/**
* Initialize the object.
*
* @param config the config Object to read initialization
* information from.
* @exception Exception
*/
void
init ( const Config & config ) throw ( Exception );
/**
* Look for the icecast stream outputs from the config file.
* Called from init()
*
* @param config the config Object to read initialization
* information from.
* @param bufferSecs number of seconds to buffer audio for
* @exception Exception
*/
void
configIceCast ( const Config & config,
unsigned int bufferSecs ) throw ( Exception );
/**
* Look for the icecast2 stream outputs from the config file.
* Called from init()
*
* @param config the config Object to read initialization
* information from.
* @param bufferSecs number of seconds to buffer audio for
* @exception Exception
*/
void
configIceCast2 ( const Config & config,
unsigned int bufferSecs ) throw ( Exception );
/**
* Look for the shoutcast stream outputs from the config file.
* Called from init()
*
* @param config the config Object to read initialization
* information from.
* @param bufferSecs number of seconds to buffer audio for
* @exception Exception
*/
void
configShoutCast ( const Config & config,
unsigned int bufferSecs ) throw ( Exception );
/**
* Look for file outputs from the config file.
* Called from init()
*
* @param config the config Object to read initialization
* information from.
* @exception Exception
*/
void
configFileCast ( const Config & config )
throw ( Exception );
/**
* Set POSIX real-time scheduling for the encoding process,
* if user permissions enable it.
*
* @exception Exception
*/
void
setRealTimeScheduling ( void ) throw ( Exception );
/**
* Set the scheduling that was before setting real-time scheduling.
* This function must be called _only_ after setRealTimeScheduling.
*
* @exception Exception
*/
void
setOriginalScheduling ( void ) throw ( Exception );
/**
* Start encoding. Spawns all encoders, opens the dsp and
* starts sending data to the encoders.
*
* @return if encoding was successful.
* @exception Exception
*/
bool
encode ( void ) throw ( Exception );
/**
* Start shouting. fork()-s a process for each output, reads
* the output of the encoders and sends them to an IceCast server.
*
* @return if shouting was successful.
* @exception Exception
*/
bool
shout ( unsigned int ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
DarkIce ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor based on a configuration object.
*
* @param config the config Object to read initialization
* information from.
* @exception Exception
*/
inline
DarkIce ( const Config & config ) throw ( Exception )
{
init( config);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~DarkIce ( void ) throw ( Exception )
{
}
/* TODO
inline
DarkIce ( const DarkIce & di ) throw ( Exception )
{
}
inline DarkIce &
operator= ( const DarkIce * di ) throw ( Exception )
{
}
*/
/**
* Run the process of recording / encoding / sending to the servers.
*
* @return 0 on success
* @exception Exception
*/
virtual int
run ( void ) throw ( Exception );
/**
* Signal to each sink we have that they need to cut what they are
* doing, and start again. For FileSinks, this usually means to
* save the archive file recorded so far, and start a new archive
* file.
*/
virtual void
cut ( void ) throw ();
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* DARK_ICE_H */

View File

@ -0,0 +1,166 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell Config
File : DarkIceConfig.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <iterator>
#include <iostream>
#include "DarkIceConfig.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/*------------------------------------------------------------------------------
* Max line size
*----------------------------------------------------------------------------*/
#define LINE_SIZE 256
/*------------------------------------------------------------------------------
* string containing all white space characters
*----------------------------------------------------------------------------*/
#define WHITE_SPACE_STR " \t"
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Get a value for a key
*----------------------------------------------------------------------------*/
const ConfigSection *
Config :: get ( const char * key ) const throw ( Exception )
{
if ( !key ) {
throw Exception( __FILE__, __LINE__, "no key");
}
TableType::const_iterator it = table.find( key);
if ( it == table.end() ) {
return 0;
}
return &(it->second);
}
/*------------------------------------------------------------------------------
* Add a configuration line
*----------------------------------------------------------------------------*/
bool
Config :: addLine ( const char * line ) throw ( Exception )
{
if ( !line ) {
throw Exception( __FILE__, __LINE__, "no line");
}
std::string::size_type ix;
std::string str( line);
/* delete everything after the first # */
if ( (ix = str.find( '#')) != str.npos ) {
str.erase( ix);
}
/* eat up all white space from the front */
if ( (ix = str.find_first_not_of( WHITE_SPACE_STR)) != str.npos ) {
str.erase( 0, ix);
}
/* eat up all white space from the end */
if ( (ix = str.find_last_not_of( WHITE_SPACE_STR)) != str.npos ) {
str.erase( ix + 1);
}
if ( !str.length() ) {
return true;
}
if ( str[0] == '[' && str[str.size()-1] == ']' ) {
// a new section starts
std::string section( str, 1, str.size()-2);
ConfigSection cSection;
std::pair<const std::string, ConfigSection>
element( section, cSection);
std::pair<TableType::iterator, bool> res;
res = table.insert( element);
currentSection = section;
return res.second;
} else {
// it's a line for the current section
TableType::iterator it = table.find( currentSection);
if ( it == table.end() ) {
throw Exception( __FILE__, __LINE__, "no current section");
}
return it->second.addLine( line);
}
}
/*------------------------------------------------------------------------------
* Add a configuration line
*----------------------------------------------------------------------------*/
void
Config :: read ( std::istream & is ) throw ( Exception )
{
char line[LINE_SIZE];
unsigned int num;
for ( num = 0; !is.fail() && !is.eof(); ++num ) {
is.getline( line, LINE_SIZE);
if ( is.eof() ) {
break;
} else if ( is.fail() ) {
throw Exception( __FILE__, __LINE__, "line too long", num);
}
addLine( line);
}
}

View File

@ -0,0 +1,209 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell Config
File : DarkIceConfig.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef CONFIG_H
#define CONFIG_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include <map>
#include <string>
#include <iostream>
#include "Referable.h"
#include "ConfigSection.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A configuration file representation. The file is of the syntax:
*
* <pre>
* [section1]
* # this is a whole line comment
* key = value
* an ugly key name = long value # this end is a comment too
*
* [section2]
* # this is a whole line comment in section 2
* key = value
* an ugly key name = long value # this end is a comment too
* </pre>
*
* also empty lines are ignored and all white space is removed
* from the front and end of keys / values
*
* Knwon problem: you can't use '#' in any part of a key / value pair
*
* @author $Author$
* @version $Revision$
*/
class Config : public virtual Referable
{
private:
/**
* Type declaration of the hash table type.
*/
typedef std::map<std::string, ConfigSection> TableType;
/**
* Hash table holding the configuration sections.
*
* @see ConfigSection
*/
TableType table;
/**
* Hash table holding the configuration sections.
*
* @see ConfigSection
*/
std::string currentSection;
protected:
public:
/**
* Default constructor.
*
* @exception Exception
*/
inline
Config ( void ) throw ( Exception )
{
}
/**
* Constructor based on an input stream.
*
* @param is configuration will be read from this input stream
* until end of stream is reached.
* @exception Exception
*/
inline
Config ( std::istream & is ) throw ( Exception )
{
read( is );
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~Config ( void ) throw ( Exception )
{
}
/* TODO
inline
Config ( const Config & di ) throw ( Exception )
{
}
inline Config &
operator= ( const Config * di ) throw ( Exception )
{
}
*/
/**
* Delete the configuration information stored in the object.
* Resets the object to a clean state.
*
* @exception Exception
*/
inline virtual void
reset ( void ) throw ( Exception )
{
table.clear();
currentSection = "";
}
/**
* Read a line of confiugration information.
*
* @param line the line to read.
* @return true if the line was correct, false otherwise.
* @exception Exception
*/
virtual bool
addLine ( const char * line ) throw ( Exception );
/**
* Read a line of confiugration information.
*
* @param is the input stream to read from
* @return true if the line was correct, false otherwise.
* @exception Exception
*/
virtual void
read ( std::istream & is ) throw ( Exception );
/**
* Get a ConfigSection by name.
*
* @param key the name of the ConfigSection
* @return the ConfigSection requested, or NULL if it doesn't exists.
* @exception Exception
*/
virtual const ConfigSection *
get ( const char * key ) const throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* CONFIG_H */

View File

@ -0,0 +1,201 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Exception.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#include "Exception.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Constructor
*----------------------------------------------------------------------------*/
Exception :: Exception ( const char * file,
unsigned int line,
const char * description1,
const char * description2,
int code ) throw ()
{
size_t len = 0;
if ( description1 ) {
len += strlen( description1);
}
if ( description2 ) {
len += strlen( description2);
}
if ( len ) {
char * str = new char[len+1];
str[0] = '\0';
if ( description1 ) {
strcat( str, description1);
}
if ( description2 ) {
strcat( str, description2);
}
init( file, line, str, code);
delete[] str;
} else {
init( file, line, 0, code);
}
}
/*------------------------------------------------------------------------------
* Constructor
*----------------------------------------------------------------------------*/
Exception :: Exception ( const char * file,
unsigned int line,
const char * description1,
const char * description2,
const char * description3,
int code ) throw ()
{
size_t len = 0;
if ( description1 ) {
len += strlen( description1);
}
if ( description2 ) {
len += strlen( description2);
}
if ( description3 ) {
len += strlen( description3);
}
if ( len ) {
char * str = new char[len+1];
str[0] = '\0';
if ( description1 ) {
strcat( str, description1);
}
if ( description2 ) {
strcat( str, description2);
}
if ( description3 ) {
strcat( str, description3);
}
init( file, line, str, code);
delete[] str;
} else {
init( file, line, 0, code);
}
}
/*------------------------------------------------------------------------------
* Initialize the class
*----------------------------------------------------------------------------*/
void
Exception :: init ( const char * file,
unsigned int line,
const char * description = 0,
int code = 0 ) throw ()
{
if ( !file ) {
this->file = 0;
} else {
size_t len;
len = strlen( file ) + 1;
this->file = new char[len];
if ( this->file ) {
memcpy( this->file, file, len);
}
}
if ( !description ) {
this->description = 0;
} else {
size_t len;
len = strlen( description ) + 1;
this->description = new char[len];
if ( this->description ) {
memcpy( this->description, description, len);
}
}
this->line = line;
this->code = code;
}
/*------------------------------------------------------------------------------
* De-initialize the class
*----------------------------------------------------------------------------*/
void
Exception :: strip ( void ) throw ()
{
if ( description ) {
delete[] description;
}
if ( file ) {
delete[] file;
}
}

View File

@ -0,0 +1,298 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Exception.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef EXCEPTION_H
#define EXCEPTION_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include <iostream>
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An exception class.
*
* This class should not depend on any other class
* should not throw any exceptions itself.
*
* Typical usage:
*
* <pre>
* throw Exception( __FILE__, __LINE__, "describe the exception", code);
* </pre>
*
* @author $Author$
* @version $Revision$
*/
class Exception
{
private:
/**
* Source file the exception was thrown in.
*/
char * file;
/**
* Line number in the source file the exception was thrown in.
*/
unsigned int line;
/**
* Textual description of the exception.
*/
char * description;
/**
* Numerical error code.
*/
int code;
/**
* Initalize the object.
*
* @param file the source file the exception was thrown in.
* @param line the line in the source file.
* @param description textual description of the exception.
* @param code numerical error code.
*/
void
init ( const char * file,
unsigned int line,
const char * description,
int code ) throw ();
/**
* De-initalize the object.
*/
void
strip () throw ();
protected:
public:
/**
* Default constructor.
*/
inline
Exception ( void ) throw ()
{
init( 0, 0, 0, 0);
}
/**
* Copy constructor.
*/
inline
Exception ( const Exception & e ) throw ()
{
init( e.file, e.line, e.description, e.code);
}
/**
* Construct by a description and error code.
*
* @param description textual description of the exception.
* @param code numerical error code.
*/
inline
Exception ( const char * description,
int code = 0 ) throw ()
{
init( 0, 0, description, code);
}
/**
* Construct by source file information, a description and error code.
*
* @param file the source file the exception was thrown in.
* @param line the line in the source file.
* @param description textual description of the exception.
* @param code numerical error code.
*/
inline
Exception ( const char * file,
unsigned int line,
const char * description = 0,
int code = 0 ) throw ()
{
init( file, line, description, code);
}
/**
* Construct by source file information, a description and error code.
* The description is constructed from two strings, any of which
* may be NULL.
*
* @param file the source file the exception was thrown in.
* @param line the line in the source file.
* @param description1 textual description of the exception part 1.
* @param description2 textual description of the exception part 2.
* @param code numerical error code.
*/
Exception ( const char * file,
unsigned int line,
const char * description1,
const char * description2,
int code = 0 ) throw ();
/**
* Construct by source file information, a description and error code.
* The description is constructed from three strings, any of
* which may be NULL.
*
* @param file the source file the exception was thrown in.
* @param line the line in the source file.
* @param description1 textual description of the exception part 1.
* @param description2 textual description of the exception part 2.
* @param description3 textual description of the exception part 3.
* @param code numerical error code.
*/
Exception ( const char * file,
unsigned int line,
const char * description1,
const char * description2,
const char * description3,
int code = 0 ) throw ();
/**
* Desctructor.
*/
inline
~Exception ( void ) throw ()
{
strip();
}
/**
* Assignment operator.
*
* @param e the Exception to assign this to.
* @return a reference to this Exception.
*/
inline Exception &
operator= ( const Exception & e ) throw ()
{
if ( this != &e ) {
strip();
init( e.file, e.line, e.description, e.code);
}
return *this;
}
/**
* Return the textual description of the Exception.
*
* @return the textual description of the Exception.
*/
inline const char *
getDescription( void ) const throw ()
{
return description;
}
/**
* Return the line number in the source file this Exception was
* thrown in.
*
* @return the line number in the source file this Exception was
* thrown in.
*/
inline unsigned int
getLine ( void ) const throw ()
{
return line;
}
/**
* Return the source file this Exception was thrown in.
*
* @return the source file this Exception was thrown in.
*/
inline const char *
getFile ( void ) const throw ()
{
return file;
}
/**
* Return the numerical code of the Exception.
*
* @return the numerical code of the Exception.
*/
inline int
getCode ( void ) const throw ()
{
return code;
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
/**
* Print an Exception to an ostream.
*
* @param os the output stream to print to.
* @param e the Exception to print.
* @return a reference to the supplied output stream.
*/
inline std::ostream &
operator<< ( std::ostream & os,
const Exception & e )
{
os << e.getFile() << ":" << e.getLine() << ": "
<< e.getDescription() << " [" << e.getCode() << "]";
return os;
}
#endif /* EXCEPTION_H */

View File

@ -0,0 +1,279 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : FaacEncoder.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// compile the whole file only if faac support configured in
#ifdef HAVE_FAAC_LIB
#include "Exception.h"
#include "Util.h"
#include "FaacEncoder.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Open an encoding session
*----------------------------------------------------------------------------*/
bool
FaacEncoder :: open ( void )
throw ( Exception )
{
if ( isOpen() ) {
close();
}
// open the underlying sink
if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__,
"faac lib opening underlying sink error");
}
char * faacVersion;
char * faacCopyright;
faacEncGetVersion(&faacVersion, &faacCopyright);
reportEvent(1, "Using faac codec version", faacVersion);
encoderHandle = faacEncOpen(getOutSampleRate(),
getInChannel(),
&inputSamples,
&maxOutputBytes);
faacEncConfiguration * faacConfig;
faacConfig = faacEncGetCurrentConfiguration(encoderHandle);
faacConfig->aacObjectType = MAIN;
faacConfig->mpegVersion = MPEG2;
faacConfig->useTns = 1;
faacConfig->shortctl = SHORTCTL_NORMAL;
faacConfig->useLfe = 0;
faacConfig->allowMidside = 1;
faacConfig->bitRate = getOutBitrate() * 1000 / getOutChannel();
faacConfig->bandWidth = lowpass;
faacConfig->quantqual = (unsigned long) (getOutQuality() * 1000.0);
faacConfig->outputFormat = 1;
faacConfig->inputFormat = FAAC_INPUT_16BIT;
if (!faacEncSetConfiguration(encoderHandle, faacConfig)) {
throw Exception(__FILE__, __LINE__,
"error configuring faac library");
}
// initialize the resampling coverter if needed
if ( converter ) {
#ifdef HAVE_SRC_LIB
converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel());
converterData.data_in = new float[converterData.input_frames*getInChannel()];
converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1);
if ((int) inputSamples > getInChannel() * converterData.output_frames) {
resampledOffset = new float[2 * inputSamples];
} else {
resampledOffset = new float[2 * getInChannel() * converterData.input_frames];
}
converterData.src_ratio = resampleRatio;
converterData.end_of_input = 0;
#else
converter->initialize( resampleRatio, getInChannel());
//needed 2x(converted input samples) to handle offsets
int outCount = 2 * getInChannel() * (inputSamples + 1);
if (resampleRatio > 1)
outCount = (int) (outCount * resampleRatio);
resampledOffset = new short int[outCount];
#endif
resampledOffsetSize = 0;
}
faacOpen = true;
return true;
}
/*------------------------------------------------------------------------------
* Write data to the encoder
*----------------------------------------------------------------------------*/
unsigned int
FaacEncoder :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
if ( !isOpen() || len == 0 ) {
return 0;
}
unsigned int channels = getInChannel();
unsigned int bitsPerSample = getInBitsPerSample();
unsigned int sampleSize = (bitsPerSample / 8) * channels;
unsigned char * b = (unsigned char*) buf;
unsigned int processed = len - (len % sampleSize);
unsigned int nSamples = processed / sampleSize;
unsigned char * faacBuf = new unsigned char[maxOutputBytes];
int samples = (int) nSamples * channels;
int processedSamples = 0;
if ( converter ) {
unsigned int converted;
#ifdef HAVE_SRC_LIB
src_short_to_float_array ((short *) b, converterData.data_in, samples);
converterData.input_frames = nSamples;
converterData.data_out = resampledOffset + (resampledOffsetSize * channels);
int srcError = src_process (converter, &converterData);
if (srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
converted = converterData.output_frames_gen;
#else
int inCount = nSamples;
short int * shortBuffer = new short int[samples];
int outCount = (int) (inCount * resampleRatio);
Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian());
converted = converter->resample( inCount,
outCount+1,
shortBuffer,
&resampledOffset[resampledOffsetSize*channels]);
delete[] shortBuffer;
#endif
resampledOffsetSize += converted;
// encode samples (if enough)
while(resampledOffsetSize - processedSamples >= inputSamples/channels) {
int outputBytes;
#ifdef HAVE_SRC_LIB
short *shortData = new short[inputSamples];
src_float_to_short_array(resampledOffset + (processedSamples * channels),
shortData, inputSamples) ;
outputBytes = faacEncEncode(encoderHandle,
(int32_t*) shortData,
inputSamples,
faacBuf,
maxOutputBytes);
delete [] shortData;
#else
outputBytes = faacEncEncode(encoderHandle,
(int32_t*) &resampledOffset[processedSamples*channels],
inputSamples,
faacBuf,
maxOutputBytes);
#endif
getSink()->write(faacBuf, outputBytes);
processedSamples+=inputSamples/channels;
}
if (processedSamples && (int) resampledOffsetSize >= processedSamples) {
resampledOffsetSize -= processedSamples;
//move least part of resampled data to beginning
if(resampledOffsetSize)
#ifdef HAVE_SRC_LIB
resampledOffset = (float *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*channels*sizeof(float));
#else
resampledOffset = (short *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*sampleSize);
#endif
}
} else {
while (processedSamples < samples) {
int outputBytes;
int inSamples = samples - processedSamples < (int) inputSamples
? samples - processedSamples
: inputSamples;
outputBytes = faacEncEncode(encoderHandle,
(int32_t*) (b + processedSamples/sampleSize),
inSamples,
faacBuf,
maxOutputBytes);
getSink()->write(faacBuf, outputBytes);
processedSamples += inSamples;
}
}
delete[] faacBuf;
return samples * sampleSize;
}
/*------------------------------------------------------------------------------
* Flush the data from the encoder
*----------------------------------------------------------------------------*/
void
FaacEncoder :: flush ( void )
throw ( Exception )
{
if ( !isOpen() ) {
return;
}
getSink()->flush();
}
/*------------------------------------------------------------------------------
* Close the encoding session
*----------------------------------------------------------------------------*/
void
FaacEncoder :: close ( void ) throw ( Exception )
{
if ( isOpen() ) {
flush();
faacEncClose(encoderHandle);
faacOpen = false;
getSink()->close();
}
}
#endif // HAVE_FAAC_LIB

View File

@ -0,0 +1,517 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : FaacEncoder.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef AAC_ENCODER_H
#define AAC_ENCODER_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_FAAC_LIB
#include <faac.h>
#else
#error configure with faac
#endif
#include "Ref.h"
#include "Exception.h"
#include "Reporter.h"
#include "AudioEncoder.h"
#include "Sink.h"
#ifdef HAVE_SRC_LIB
#include <samplerate.h>
#else
#include "aflibConverter.h"
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A class representing faac AAC encoder.
*
* @author $Author$
* @version $Revision$
*/
class FaacEncoder : public AudioEncoder, public virtual Reporter
{
private:
/**
* A flag to indicate if the encoding session is open.
*/
bool faacOpen;
/**
* The handle to the AAC encoder instance.
*/
faacEncHandle encoderHandle;
/**
* The maximum number of input samples to supply to the encoder.
*/
unsigned long inputSamples;
/**
* The maximum number of output bytes the encoder returns in one call.
*/
unsigned long maxOutputBytes;
/**
* Lowpass filter. Sound frequency in Hz, from where up the
* input is cut.
*/
int lowpass;
/**
* Resample ratio
*/
double resampleRatio;
/**
* sample rate converter object for possible resampling
*/
#ifdef HAVE_SRC_LIB
SRC_STATE *converter;
SRC_DATA converterData;
float *resampledOffset;
#else
aflibConverter *converter;
short *resampledOffset;
#endif
unsigned int resampledOffsetSize;
/**
* Initialize the object.
*
* @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut.
* If 0, faac's default values are used,
* which depends on the out sample rate.
* @exception Exception
*/
inline void
init ( int lowpass) throw (Exception)
{
this->faacOpen = false;
this->lowpass = lowpass;
if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) {
throw Exception( __FILE__, __LINE__,
"specified bits per sample not supported",
getInBitsPerSample() );
}
if ( getInChannel() != 1 && getInChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of input channels for the encoder",
getInChannel() );
}
if ( getOutChannel() != 1 && getOutChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of output channels for the encoder",
getOutChannel() );
}
if ( getInChannel() != getOutChannel() ) {
throw Exception( __FILE__, __LINE__,
"input channels and output channels do not match");
}
if ( getOutSampleRate() == getInSampleRate() ) {
resampleRatio = 1;
converter = 0;
} else if (getInBitsPerSample() == 16) {
resampleRatio = ( (double) getOutSampleRate() /
(double) getInSampleRate() );
// Determine if we can use linear interpolation.
// The inverse of the ratio must be a power of two for linear mode to
// be of sufficient quality.
bool useLinear = true;
double inverse = 1 / resampleRatio;
int integer = (int) inverse;
// Check that the inverse of the ratio is an integer
if( integer == inverse ) {
while( useLinear && integer ) { // Loop through the bits
// If the lowest order bit is not the only one set
if( integer & 1 && integer != 1 ) {
// Not a power of two; cannot use linear
useLinear = false;
} else {
// Shift all the bits over and try again
integer >>= 1;
}
}
} else {
useLinear = false;
}
// If we get here and useLinear is still true, then we have
// a power of two.
// open the aflibConverter in
// - high quality
// - linear or quadratic (non-linear) based on algorithm
// - not filter interpolation
#ifdef HAVE_SRC_LIB
int srcError = 0;
converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST,
getInChannel(), &srcError);
if(srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
#else
converter = new aflibConverter( true, useLinear, false);
#endif
} else {
throw Exception( __FILE__, __LINE__,
"specified bits per sample with samplerate conversion not supported",
getInBitsPerSample() );
}
}
/**
* De-initialize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
if ( converter ) {
#ifdef HAVE_SRC_LIB
delete [] converterData.data_in;
src_delete (converter);
#else
delete converter;
#endif
delete [] resampledOffset;
}
}
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
FaacEncoder ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor.
*
* @param sink the sink to send mp3 output to
* @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input.
* @param inBigEndian shows if the input is big or little endian
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, inSampleRate is used.
* @param outChannel number of channels of the output.
* If 0, inChannel is used.
* @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut.
* If 0, faac's default values are used,
* which depends on the out sample rate.
* @exception Exception
*/
inline
FaacEncoder ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample,
unsigned int inChannel,
bool inBigEndian,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
int lowpass = 0)
throw ( Exception )
: AudioEncoder ( sink,
inSampleRate,
inBitsPerSample,
inChannel,
inBigEndian,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( lowpass);
}
/**
* Constructor.
*
* @param sink the sink to send mp3 output to
* @param as get input sample rate, bits per sample and channels
* from this AudioSource.
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, input sample rate is used.
* @param outChannel number of channels of the output.
* If 0, input channel is used.
* @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut.
* If 0, faac's default values are used,
* which depends on the out sample rate.
* @exception Exception
*/
inline
FaacEncoder ( Sink * sink,
const AudioSource * as,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
int lowpass = 0)
throw ( Exception )
: AudioEncoder ( sink,
as,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( lowpass);
}
/**
* Copy constructor.
*
* @param encoder the FaacEncoder to copy.
*/
inline
FaacEncoder ( const FaacEncoder & encoder )
throw ( Exception )
: AudioEncoder( encoder )
{
init( encoder.lowpass);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~FaacEncoder ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
strip();
}
/**
* Assignment operator.
*
* @param encoder the FaacEncoder to assign this to.
* @return a reference to this FaacEncoder.
* @exception Exception
*/
inline virtual FaacEncoder &
operator= ( const FaacEncoder & encoder ) throw ( Exception )
{
if ( this != &encoder ) {
strip();
AudioEncoder::operator=( encoder);
init( encoder.lowpass);
}
return *this;
}
/**
* Get the version string of the underlying faac library.
*
* @return the version string of the underlying faac library.
*/
inline const char *
getFaacVersion( void )
{
char * id;
char * copyright;
faacEncGetVersion(&id, &copyright);
return id;
}
/**
* Check whether encoding is in progress.
*
* @return true if encoding is in progress, false otherwise.
*/
inline virtual bool
isRunning ( void ) const throw ()
{
return isOpen();
}
/**
* Start encoding. This function returns as soon as possible,
* with encoding started in the background.
*
* @return true if encoding has started, false otherwise.
* @exception Exception
*/
inline virtual bool
start ( void ) throw ( Exception )
{
return open();
}
/**
* Stop encoding. Stops the encoding running in the background.
*
* @exception Exception
*/
inline virtual void
stop ( void ) throw ( Exception )
{
return close();
}
/**
* Open an encoding session.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the encoding session is open.
*
* @return true if the encoding session is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return faacOpen;
}
/**
* Check if the encoder is ready to accept data.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the encoder is ready to accept data,
* false otherwise.
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
if ( !isOpen() ) {
return false;
}
return true;
}
/**
* Write data to the encoder.
* Buf is expected to be a sequence of big-endian 16 bit values,
* with left and right channels interleaved. Len is the number of
* bytes, must be a multiple of 4.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* Flush all data that was written to the encoder to the underlying
* connection.
*
* @exception Exception
*/
virtual void
flush ( void ) throw ( Exception );
/**
* Close the encoding session.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* AAC_ENCODER_H */

View File

@ -0,0 +1,89 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : FileCast.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#else
#error need stdio.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#include "Exception.h"
#include "Source.h"
#include "Sink.h"
#include "Util.h"
#include "FileCast.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Open the connection
*----------------------------------------------------------------------------*/
bool
FileCast :: open ( void ) throw ( Exception )
{
if ( isOpen() ) {
return false;
}
if ( !targetFile->open() ) {
return false;
}
return true;
}

View File

@ -0,0 +1,274 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : FileCast.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef FILE_CAST_H
#define FILE_CAST_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Ref.h"
#include "Sink.h"
#include "CastSink.h"
#include "FileSink.h"
#include "FileCast.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Class representing output to a local file.
*
* @author $Author$
* @version $Revision$
*/
class FileCast : public CastSink
{
private:
/**
* The file to send the encoded data to.
*/
Ref<FileSink> targetFile;
/**
* Initalize the object.
*
* @param targetFile the file to send the encoded data to.
* @exception Exception
*/
inline void
init ( FileSink * targetFile )
throw ( Exception )
{
this->targetFile = targetFile;
}
/**
* De-initalize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
}
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
FileCast ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Log in to the server using the socket avialable.
* No need to log in to a file.
*
* @return true if login was successful, false otherwise.
* @exception Exception
*/
inline virtual bool
sendLogin ( void ) throw ( Exception )
{
return true;
}
public:
/**
* Constructor.
*
* @param targetFile the file to send all the data to.
* @exception Exception
*/
inline
FileCast ( FileSink * targetFile )
throw ( Exception )
: CastSink( 0, 0, 0)
{
init( targetFile );
}
/**
* Copy constructor.
*
* @param cs the FileCast to copy.
*/
inline
FileCast( const FileCast & cs ) throw ( Exception )
{
init( targetFile.get() );
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~FileCast( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param cs the FileCast to assign this to.
* @return a reference to this FileCast.
* @exception Exception
*/
inline virtual FileCast &
operator= ( const FileCast & cs ) throw ( Exception )
{
if ( this != &cs ) {
strip();
init( targetFile.get() );
}
return *this;
}
/**
* Open the FileCast.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the FileCast is open.
*
* @return true if the FileCast is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return targetFile->isOpen();
}
/**
* Check if the FileCast is ready to accept data.
* Blocks until the specified time for data to be available.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the FileCast is ready to accept data,
* false otherwise.
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
return targetFile->canWrite( sec, usec);
}
/**
* Write data to the FileCast.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
inline virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception )
{
return targetFile->write( buf, len);
}
/**
* Flush all data that was written to the FileCast to the server.
*
* @exception Exception
*/
inline virtual void
flush ( void ) throw ( Exception )
{
return targetFile->flush();
}
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
inline virtual void
cut ( void ) throw ()
{
targetFile->cut();
}
/**
* Close the FileCast.
*
* @exception Exception
*/
inline virtual void
close ( void ) throw ( Exception )
{
return targetFile->close();
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* FILE_CAST_H */

View File

@ -0,0 +1,384 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : FileSink.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
#error need stdlib.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#else
#error need errno.h
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#else
#error need sys/stat.h
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#error need fcntl.h
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#error need sys/time.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#include <iostream>
#include <sstream>
#include <fstream>
#include "Util.h"
#include "Exception.h"
#include "FileSink.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
FileSink :: init ( const char * configName,
const char * name ) throw ( Exception )
{
this->configName = Util::strDup(configName);
fileName = Util::strDup(name);
fileDescriptor = 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
FileSink :: strip ( void) throw ( Exception )
{
if ( isOpen() ) {
close();
}
delete[] fileName;
}
/*------------------------------------------------------------------------------
* Copy Constructor
*----------------------------------------------------------------------------*/
FileSink :: FileSink ( const FileSink & fs ) throw ( Exception )
: Sink( fs )
{
int fd;
init( fs.configName, fs.fileName);
if ( (fd = fs.fileDescriptor ? dup( fs.fileDescriptor) : 0) == -1 ) {
strip();
throw Exception( __FILE__, __LINE__, "dup failure");
}
fileDescriptor = fd;
}
/*------------------------------------------------------------------------------
* Assignment operator
*----------------------------------------------------------------------------*/
FileSink &
FileSink :: operator= ( const FileSink & fs ) throw ( Exception )
{
if ( this != &fs ) {
int fd;
/* first strip */
strip();
/* then build up */
Sink::operator=( fs );
init( fs.configName, fs.fileName);
if ( (fd = fs.fileDescriptor ? dup( fs.fileDescriptor) : 0) == -1 ) {
strip();
throw Exception( __FILE__, __LINE__, "dup failure");
}
fileDescriptor = fd;
}
return *this;
}
/*------------------------------------------------------------------------------
* Check whether a file exists and is regular file
*----------------------------------------------------------------------------*/
bool
FileSink :: exists ( void ) const throw ()
{
struct stat st;
if ( stat( (const char*)fileName, &st) == -1 ) {
return false;
}
return S_ISREG( st.st_mode);
}
/*------------------------------------------------------------------------------
* Create a file, truncate if already exists
*----------------------------------------------------------------------------*/
bool
FileSink :: create ( void ) throw ( Exception )
{
int fd;
if ( isOpen() ) {
return false;
}
/* filemode default to 0666 */
const int filemode = (S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH|S_IWOTH) ;
/* create the file */
if ( (fd = ::creat( fileName, filemode )) == -1 ) {
reportEvent( 3, "can't create file", fileName, errno);
return false;
}
::close( fd);
return true;
}
/*------------------------------------------------------------------------------
* Open the file
*----------------------------------------------------------------------------*/
bool
FileSink :: open ( void ) throw ( Exception )
{
if ( isOpen() ) {
return false;
}
if ( (fileDescriptor = ::open( fileName, O_WRONLY | O_TRUNC, 0)) == -1 ) {
fileDescriptor = 0;
return false;
}
return true;
}
/*------------------------------------------------------------------------------
* Check whether the file can be written to
*----------------------------------------------------------------------------*/
bool
FileSink :: canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
fd_set fdset;
struct timespec timespec;
sigset_t sigset;
int ret;
if ( !isOpen() ) {
return false;
}
FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset);
timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( fileDescriptor + 1, NULL, &fdset, NULL, &timespec, &sigset);
if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error");
}
return ret > 0;
}
/*------------------------------------------------------------------------------
* Write to the FileSink
*----------------------------------------------------------------------------*/
unsigned int
FileSink :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
ssize_t ret;
if ( !isOpen() ) {
return 0;
}
ret = ::write( fileDescriptor, buf, len);
if ( ret == -1 ) {
if ( errno == EAGAIN ) {
ret = 0;
} else {
throw Exception( __FILE__, __LINE__, "write error", errno);
}
}
return ret;
}
/*------------------------------------------------------------------------------
* Get the file name to where to move the data saved so far.
* The trick is to read the file name from a file named
* /tmp/darkice.$configName.$PID , where:
* - $configName is the name of the configuration section for this file sink
* - $PID is the current process id
*----------------------------------------------------------------------------*/
std::string
FileSink :: getArchiveFileName ( void ) throw ( Exception )
{
pid_t pid = getpid();
std::stringstream metaFileName;
metaFileName << "/tmp/darkice." << configName << "." << pid;
std::ifstream ifs(metaFileName.str().c_str());
if (!ifs.good()) {
throw Exception(__FILE__, __LINE__,
"can't find file ", metaFileName.str().c_str(), 0);
}
std::string archiveFileName;
ifs >> archiveFileName;
ifs.close();
return archiveFileName;
}
/*------------------------------------------------------------------------------
* Cut what we've done so far, and start anew.
*----------------------------------------------------------------------------*/
void
FileSink :: cut ( void ) throw ()
{
flush();
close();
try {
std::string archiveFileName = getArchiveFileName();
if (::rename(fileName, archiveFileName.c_str()) != 0) {
reportEvent(2, "couldn't move file", fileName,
"to", archiveFileName);
}
} catch ( Exception &e ) {
reportEvent(2, "error during archive cut", e);
}
create();
open();
}
/*------------------------------------------------------------------------------
* Close the FileSink
*----------------------------------------------------------------------------*/
void
FileSink :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
flush();
::close( fileDescriptor);
fileDescriptor = 0;
}

View File

@ -0,0 +1,278 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : FileSink.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef FILE_SINK_H
#define FILE_SINK_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Reporter.h"
#include "Sink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* File data output
*
* @author $Author$
* @version $Revision$
*/
class FileSink : public Sink, public virtual Reporter
{
private:
/**
* The name of the configuration related to
* this file sink. something like "file-0" or "file-2".
*/
char * configName;
/**
* Name of the file represented by the FileSink.
*/
char * fileName;
/**
* Initialize the object.
*
* @param configName the name of the configuration related to
* this file sink. something like "file-0" or "file-2".
* @param name name of the file to be represented by the object.
* @exception Exception
*/
void
init ( const char * configName,
const char * name ) throw ( Exception );
/**
* De-initialize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
/**
* Get the file name to where to move the data saved so far.
* Used in cut().
*
* @return the file name where to move the data saved so far.
* @throws Exception on file operation errors
*/
std::string
getArchiveFileName( void ) throw ( Exception );
protected:
/**
* Low-level file descriptor for the file represented by this object.
*/
int fileDescriptor;
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
FileSink ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor by a file name.
*
* @param configName the name of the configuration related to
* this file sink. something like "file-0" or "file-2".
* @param name name of the file to be represented by the object.
* @exception Exception
*/
inline
FileSink( const char * configName,
const char * name ) throw ( Exception )
{
init( configName, name);
}
/**
* Copy constructor.
*
* @param fsink the FileSink to copy.
* @exception Exception
*/
FileSink( const FileSink & fsink ) throw ( Exception );
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~FileSink( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param fs the FileSink to assign to this object.
* @return a reference to this object.
* @exception Exception
*/
virtual FileSink &
operator= ( const FileSink & fs ) throw ( Exception );
/**
* Get the file name this FileSink represents.
*
* @return the file name this FileSink represents.
*/
inline const char *
getFileName ( void ) const throw ()
{
return fileName;
}
/**
* Check for the existence of the file this FileSink represents.
*
* @return true if the file exists and is a regular file,
* false otherwise.
*/
virtual bool
exists ( void ) const throw ();
/**
* Create the file.
*
* @return true if creation was successful, false otherwise.
* @exception Exception
*/
virtual bool
create ( void ) throw ( Exception );
/**
* Open the file. Truncates the file.
*
* @return true if opening was successful, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the FileSink is open.
*
* @return true if the FileSink is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return fileDescriptor != 0;
}
/**
* Check if the FileSink is ready to accept data.
* Blocks until the specified time for data to be available.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the Sink is ready to accept data, false otherwise.
* @exception Exception
*/
virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Write data to the FileSink.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* This is a no-op in this FileSink.
*
* @exception Exception
*/
inline virtual void
flush ( void ) throw ( Exception )
{
}
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
virtual void
cut ( void ) throw ();
/**
* Close the FileSink.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* FILE_SINK_H */

View File

@ -0,0 +1,270 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : FileSource.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#else
#error need sys/stat.h
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#error need fcntl.h
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#error need sys/time.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#include "Exception.h"
#include "Util.h"
#include "FileSource.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
FileSource :: init ( const char * name ) throw ( Exception )
{
fileName = Util::strDup( name);
fileDescriptor = 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
FileSource :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
delete[] fileName;
fileDescriptor = 0;
}
/*------------------------------------------------------------------------------
* Copy Constructor
*----------------------------------------------------------------------------*/
FileSource :: FileSource ( const FileSource & fs ) throw ( Exception )
{
init( fs.fileName);
fileDescriptor = fs.fileDescriptor ? dup( fs.fileDescriptor) : 0;
if ( fileDescriptor == -1 ) {
strip();
throw Exception( __FILE__, __LINE__, "dup failure");
}
}
/*------------------------------------------------------------------------------
* Assignment operator
*----------------------------------------------------------------------------*/
FileSource &
FileSource :: operator= ( const FileSource & fs ) throw ( Exception )
{
if ( this != &fs ) {
init( fs.fileName);
fileDescriptor = fs.fileDescriptor ? dup( fs.fileDescriptor) : 0;
if ( fileDescriptor == -1 ) {
strip();
throw Exception( __FILE__, __LINE__, "dup failure");
}
}
return *this;
}
/*------------------------------------------------------------------------------
* Check wether a file exists
*----------------------------------------------------------------------------*/
bool
FileSource :: exists ( void ) const throw ()
{
struct stat st;
if ( stat( (const char*)fileName, &st) == -1 ) {
return false;
}
return true;
}
/*------------------------------------------------------------------------------
* Open the source
*----------------------------------------------------------------------------*/
bool
FileSource :: open ( void ) throw ( Exception )
{
if ( isOpen() ) {
return false;
}
if ( (fileDescriptor = ::open( fileName, O_RDONLY)) == -1 ) {
fileDescriptor = 0;
return false;
}
return true;
}
/*------------------------------------------------------------------------------
* Check wether read() would return anything
*----------------------------------------------------------------------------*/
bool
FileSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
fd_set fdset;
struct timespec timespec;
sigset_t sigset;
int ret;
if ( !isOpen() ) {
return false;
}
FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset);
timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( fileDescriptor + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error");
}
return ret > 0;
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
FileSource :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
ssize_t ret;
if ( !isOpen() ) {
return 0;
}
ret = ::read( fileDescriptor, buf, len);
if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "read error");
}
return ret;
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
FileSource :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
::close( fileDescriptor);
fileDescriptor = 0;
}

View File

@ -0,0 +1,226 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : IceCast.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#else
#error need stdio.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#else
#error need math.h
#endif
#include "Exception.h"
#include "Source.h"
#include "Sink.h"
#include "Util.h"
#include "IceCast.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/*------------------------------------------------------------------------------
* Size of string conversion buffer
*----------------------------------------------------------------------------*/
#define STRBUF_SIZE 32
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
IceCast :: init ( const char * mountPoint,
const char * description,
const char * remoteDumpFile )
throw ( Exception )
{
this->mountPoint = Util::strDup( mountPoint);
this->description = description ? Util::strDup( description) : 0;
this->remoteDumpFile = remoteDumpFile ? Util::strDup( remoteDumpFile) : 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
IceCast :: strip ( void ) throw ( Exception )
{
delete[] mountPoint;
if ( description ) {
delete[] description;
}
if ( remoteDumpFile ) {
delete[] remoteDumpFile;
}
}
/*------------------------------------------------------------------------------
* Log in to the IceCast server
*----------------------------------------------------------------------------*/
bool
IceCast :: sendLogin ( void ) throw ( Exception )
{
Sink * sink = getSink();
Source * source = getSocket();
const char * str;
char resp[STRBUF_SIZE];
unsigned int len;
if ( !source->isOpen() ) {
return false;
}
if ( !sink->isOpen() ) {
return false;
}
/* send the request, a string like:
* "SOURCE <password> /<mountpoint>\n" */
str = "SOURCE ";
sink->write( str, strlen( str));
str = getPassword();
sink->write( str, strlen( str));
str = " /";
sink->write( str, strlen( str));
str = getMountPoint();
sink->write( str, strlen( str));
/* send the x-audiocast headers */
str = "\nx-audiocast-bitrate: ";
sink->write( str, strlen( str));
if ( log10(getBitRate()) >= (STRBUF_SIZE-2) ) {
throw Exception( __FILE__, __LINE__,
"bitrate does not fit string buffer", getBitRate());
}
sprintf( resp, "%d", getBitRate());
sink->write( resp, strlen( resp));
str = "\nx-audiocast-public: ";
sink->write( str, strlen( str));
str = getIsPublic() ? "1" : "0";
sink->write( str, strlen( str));
if ( getName() ) {
str = "\nx-audiocast-name: ";
sink->write( str, strlen( str));
str = getName();
sink->write( str, strlen( str));
}
if ( getDescription() ) {
str = "\nx-audiocast-description: ";
sink->write( str, strlen( str));
str = getDescription();
sink->write( str, strlen( str));
}
if ( getUrl() ) {
str = "\nx-audiocast-url: ";
sink->write( str, strlen( str));
str = getUrl();
sink->write( str, strlen( str));
}
if ( getGenre() ) {
str = "\nx-audiocast-genre: ";
sink->write( str, strlen( str));
str = getGenre();
sink->write( str, strlen( str));
}
if ( getRemoteDumpFile() ) {
str = "\nx-audiocast-dumpfile: ";
sink->write( str, strlen( str));
str = getRemoteDumpFile();
sink->write( str, strlen( str));
}
str = "\n\n";
sink->write( str, strlen( str));
sink->flush();
/* read the anticipated response: "OK" */
len = source->read( resp, STRBUF_SIZE);
reportEvent(5,resp);
if ( Util::strEq( resp, "ERROR - Bad Password",20) ) {
throw Exception( __FILE__, __LINE__,
"Icecast - wrong password");
}
if ( Util::strEq( resp, "ERROR - Mount Point Taken or Inv",32) ) {
throw Exception( __FILE__, __LINE__,
"Icecast - Mount point taken or invalid");
}
if ( len < 2 || resp[0] != 'O' || resp[1] != 'K' ) {
return false;
}
/* suck anything that the other side has to say */
while ( source->canRead( 0, 0) &&
(len = source->read( resp, STRBUF_SIZE)) ) {
;
}
return true;
}

View File

@ -0,0 +1,259 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : IceCast.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef ICE_CAST_H
#define ICE_CAST_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Sink.h"
#include "TcpSocket.h"
#include "CastSink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Class representing output to an IceCast server with
* x-audiocast login
*
* @author $Author$
* @version $Revision$
*/
class IceCast : public CastSink
{
private:
/**
* Mount point of the stream on the server.
*/
char * mountPoint;
/**
* Remote dump file if any.
*/
char * remoteDumpFile;
/**
* Description of the stream.
*/
char * description;
/**
* Initalize the object.
*
* @param mountPoint mount point of the stream on the server.
* @param remoteDumpFile remote dump file (may be NULL).
* @param description description of the stream.
* @exception Exception
*/
void
init ( const char * mountPoint,
const char * description,
const char * remoteDumpFile )
throw ( Exception );
/**
* De-initalize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
IceCast ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Log in to the server using the socket avialable.
*
* @return true if login was successful, false otherwise.
* @exception Exception
*/
virtual bool
sendLogin ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param socket socket connection to the server.
* @param password password to the server.
* @param mountPoint mount point of the stream on the server.
* @param remoteDumpFile remote dump file (may be NULL).
* @param name name of the stream.
* @param description description of the stream.
* @param url URL associated with the stream.
* @param genre genre of the stream.
* @param bitRate bitrate of the stream (e.g. mp3 bitrate).
* @param isPublic is the stream public?
* @param streamDump an optional sink to dump the binary stream
* data to.
* @param bufferDuration duration of the BufferedSink buffer
* in seconds.
* @exception Exception
*/
inline
IceCast ( TcpSocket * socket,
const char * password,
const char * mountPoint,
unsigned int bitRate,
const char * name = 0,
const char * description = 0,
const char * url = 0,
const char * genre = 0,
bool isPublic = false,
const char * remoteDumpFile = 0,
Sink * streamDump = 0 )
throw ( Exception )
: CastSink( socket,
password,
bitRate,
name,
url,
genre,
isPublic,
streamDump )
{
init( mountPoint, description, remoteDumpFile);
}
/**
* Copy constructor.
*
* @param cs the IceCast to copy.
*/
inline
IceCast( const IceCast & cs ) throw ( Exception )
: CastSink( cs )
{
init( cs.getMountPoint(),
cs.getDescription(),
cs.getRemoteDumpFile() );
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~IceCast( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param cs the IceCast to assign this to.
* @return a reference to this IceCast.
* @exception Exception
*/
inline virtual IceCast &
operator= ( const IceCast & cs ) throw ( Exception )
{
if ( this != &cs ) {
strip();
CastSink::operator=( cs );
init( cs.getMountPoint(),
cs.getDescription(),
cs.getRemoteDumpFile() );
}
return *this;
}
/**
* Get the mount point of the stream on the server.
*
* @return the mount point of the stream on the server.
*/
inline const char *
getMountPoint ( void ) const throw ()
{
return mountPoint;
}
/**
* Get the remote dump file if any.
*
* @return the remote dump file. May be NULL.
*/
inline const char *
getRemoteDumpFile ( void ) const throw ()
{
return remoteDumpFile;
}
/**
* Get the description of the stream.
*
* @return the description of the stream.
*/
inline const char *
getDescription ( void ) const throw ()
{
return description;
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* ICE_CAST_H */

View File

@ -0,0 +1,273 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : IceCast2.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#else
#error need stdio.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#else
#error need math.h
#endif
#include "Exception.h"
#include "Source.h"
#include "Sink.h"
#include "Util.h"
#include "IceCast2.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/*------------------------------------------------------------------------------
* Expected positive response from server begins like this.
*----------------------------------------------------------------------------*/
static const char responseOK[] = "HTTP/1.0 200";
static const char responseWrongPasswd[] = "HTTP/1.0 401";
static const char responseForbidden[] = "HTTP/1.0 403";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
IceCast2 :: init ( StreamFormat format,
const char * mountPoint,
const char * description )
throw ( Exception )
{
this->format = format;
this->mountPoint = Util::strDup( mountPoint);
this->description = description ? Util::strDup( description) : 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
IceCast2 :: strip ( void ) throw ( Exception )
{
delete[] mountPoint;
if ( description ) {
delete[] description;
}
}
/*------------------------------------------------------------------------------
* Log in to the IceCast2 server
*----------------------------------------------------------------------------*/
bool
IceCast2 :: sendLogin ( void ) throw ( Exception )
{
Sink * sink = getSink();
Source * source = getSocket();
const char * str;
const int buflen = 1024; // some small buffer size
char resp[buflen]; // a little buffer
unsigned int len;
unsigned int lenExpected;
if ( !source->isOpen() ) {
return false;
}
if ( !sink->isOpen() ) {
return false;
}
// send the request, a string like:
// "SOURCE <mountpoint> ICE/1.0"
str = "SOURCE /";
sink->write( str, strlen( str));
str = getMountPoint();
sink->write( str, strlen( str));
str = " HTTP/1.0";
sink->write( str, strlen( str));
// send the content type, Ogg Vorbis
str = "\nContent-type: ";
sink->write( str, strlen( str));
switch ( format ) {
case mp3:
case mp2:
str = "audio/mpeg";
break;
case oggVorbis:
str = "application/ogg";
break;
case oggOpus:
str = "application/ogg";
break;
case aac:
str = "audio/aac";
break;
case aacp:
str = "audio/aacp";
break;
default:
throw Exception( __FILE__, __LINE__,
"unsupported stream format", format);
break;
}
sink->write( str, strlen( str));
// send the authentication info
str = "\nAuthorization: Basic ";
sink->write( str, strlen(str));
{
// send source:<password> encoded as base64
const char * source = "source:";
const char * pwd = getPassword();
char * tmp = new char[Util::strLen(source) +
Util::strLen(pwd) + 1];
Util::strCpy( tmp, source);
Util::strCat( tmp, pwd);
char * base64 = Util::base64Encode( tmp);
delete[] tmp;
sink->write( base64, strlen(base64));
delete[] base64;
}
// send user agent info
str = "\nUser-Agent: DarkIce/" VERSION " (http://code.google.com/p/darkice/)";
sink->write( str, strlen( str));
// send the ice- headers
str = "\nice-bitrate: ";
sink->write( str, strlen( str));
sprintf( resp, "%d", getBitRate());
sink->write( resp, strlen( resp));
str = "\nice-public: ";
sink->write( str, strlen( str));
str = getIsPublic() ? "1" : "0";
sink->write( str, strlen( str));
if ( getName() ) {
str = "\nice-name: ";
sink->write( str, strlen( str));
str = getName();
sink->write( str, strlen( str));
}
if ( getDescription() ) {
str = "\nice-description: ";
sink->write( str, strlen( str));
str = getDescription();
sink->write( str, strlen( str));
}
if ( getUrl() ) {
str = "\nice-url: ";
sink->write( str, strlen( str));
str = getUrl();
sink->write( str, strlen( str));
}
if ( getGenre() ) {
str = "\nice-genre: ";
sink->write( str, strlen( str));
str = getGenre();
sink->write( str, strlen( str));
}
str = "\r\n\r\n";
sink->write( str, strlen( str));
sink->flush();
// read the response, expected response begins with responseOK
lenExpected = Util::strLen( responseOK);
if ( (len = source->read( resp, buflen )) < lenExpected ) {
return false; // short read, no need to continue
}
resp[lenExpected] = '\x00'; // end string, truncate to expected length
reportEvent(5,resp);
if ( Util::strEq( resp, responseWrongPasswd) ) {
throw Exception( __FILE__, __LINE__,
"Icecast2 - wrong password");
}
if ( Util::strEq( resp, responseForbidden) ) {
throw Exception( __FILE__, __LINE__,
"Icecast2 - forbidden. Is the mountpoint occupied, or maximum sources reached?");
}
if ( !Util::strEq( resp, responseOK) ) {
// some unexpected response from server
throw Exception( __FILE__, __LINE__,
"Icecast2 - Unexpected response from server");
}
// suck anything that the other side has to say
while ( source->canRead( 0, 0) &&
(len = source->read( resp, buflen )));
// all is well, we are connected
return true;
}

View File

@ -0,0 +1,267 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : IceCast2.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef ICE_CAST2_H
#define ICE_CAST2_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Sink.h"
#include "TcpSocket.h"
#include "CastSink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Class representing output to an IceCast2 server with
* ice login
*
* @author $Author$
* @version $Revision$
*/
class IceCast2 : public CastSink
{
public:
/**
* Type for specifying the format of the stream.
*/
enum StreamFormat { mp3, mp2, oggVorbis, oggOpus, aac, aacp };
private:
/**
* The format of the stream.
*/
StreamFormat format;
/**
* Mount point of the stream on the server.
*/
char * mountPoint;
/**
* Description of the stream.
*/
char * description;
/**
* Initalize the object.
*
* @param mountPoint mount point of the stream on the server.
* @param remoteDumpFile remote dump file (may be NULL).
* @param description description of the stream.
* @exception Exception
*/
void
init ( StreamFormat format,
const char * mountPoint,
const char * description )
throw ( Exception );
/**
* De-initalize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
IceCast2 ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Log in to the server using the socket avialable.
*
* @return true if login was successful, false otherwise.
* @exception Exception
*/
virtual bool
sendLogin ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param socket socket connection to the server.
* @param password password to the server.
* @param mountPoint mount point of the stream on the server.
* @param format the format of the stream.
* @param name name of the stream.
* @param description description of the stream.
* @param url URL associated with the stream.
* @param genre genre of the stream.
* @param bitRate bitrate of the stream (e.g. mp3 bitrate).
* @param isPublic is the stream public?
* @param streamDump an optional sink to dump the binary stream
* data to.
* @param bufferDuration duration of the BufferedSink buffer
* in seconds.
* @exception Exception
*/
inline
IceCast2 ( TcpSocket * socket,
const char * password,
const char * mountPoint,
StreamFormat format,
unsigned int bitRate,
const char * name = 0,
const char * description = 0,
const char * url = 0,
const char * genre = 0,
bool isPublic = false,
Sink * streamDump = 0 )
throw ( Exception )
: CastSink( socket,
password,
bitRate,
name,
url,
genre,
isPublic,
streamDump )
{
init( format, mountPoint, description);
}
/**
* Copy constructor.
*
* @param cs the IceCast2 to copy.
*/
inline
IceCast2( const IceCast2 & cs ) throw ( Exception )
: CastSink( cs )
{
init( cs.getFormat(),
cs.getMountPoint(),
cs.getDescription() );
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~IceCast2( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param cs the IceCast2 to assign this to.
* @return a reference to this IceCast2.
* @exception Exception
*/
inline virtual IceCast2 &
operator= ( const IceCast2 & cs ) throw ( Exception )
{
if ( this != &cs ) {
strip();
CastSink::operator=( cs );
init( cs.getFormat(),
cs.getMountPoint(),
cs.getDescription() );
}
return *this;
}
/**
* Get the format of the stream.
*
* @return the format of the stream.
*/
inline StreamFormat
getFormat ( void ) const throw ()
{
return format;
}
/**
* Get the mount point of the stream on the server.
*
* @return the mount point of the stream on the server.
*/
inline const char *
getMountPoint ( void ) const throw ()
{
return mountPoint;
}
/**
* Get the description of the stream.
*
* @return the description of the stream.
*/
inline const char *
getDescription ( void ) const throw ()
{
return description;
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* ICE_CAST2_H */

View File

@ -0,0 +1,506 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Copyright (c) 2005 Nicholas Humfrey. All rights reserved.
Tyrell DarkIce
File : JackDspSource.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "AudioSource.h"
#ifdef SUPPORT_JACK_DSP
// only compile this code if there is support for it
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#else
#error need stdio.h
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#else
#error need math.h
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
#error needs stdlib.h
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#else
#error need limits.h
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#include <climits>
#include "Util.h"
#include "Exception.h"
#include "JackDspSource.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
JackDspSource :: init ( const char* name ) throw ( Exception )
{
// Set defaults
ports[0] = NULL; // Left Port
ports[1] = NULL; // Right Port
rb[0] = NULL; // Left Ring Buffer
rb[1] = NULL; // Right Ring Buffer
client = NULL;
auto_connect = false; // Default is to not auto connect the JACK ports
tmp_buffer = NULL; // Buffer big enough for one 'read' of audio
// Auto connect the ports ?
if ( Util::strEq( name, "jack_auto", 9) ) {
auto_connect = true;
}
// Check the sample size
if (getBitsPerSample() != 16) {
throw Exception( __FILE__, __LINE__,
"JackDspSource doesn't support non 16-bit samples");
}
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
JackDspSource :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
// Free the temporary buffer
if (tmp_buffer) {
free(tmp_buffer);
tmp_buffer = NULL;
}
}
/*------------------------------------------------------------------------------
* Attempt to connect up the JACK ports automatically
* - Just connect left&right to the first two output ports we find
*----------------------------------------------------------------------------*/
void
JackDspSource :: do_auto_connect ( void ) throw ( Exception )
{
const char **all_ports;
unsigned int ch = 0;
int i;
Reporter::reportEvent( 10, "JackDspSource :: do_auto_connect");
// Get a list of all the jack ports
all_ports = jack_get_ports (client, NULL, NULL, JackPortIsOutput);
if (!ports) {
throw Exception( __FILE__, __LINE__, "jack_get_ports() returned NULL.");
}
// Step through each port name
for (i = 0; all_ports[i]; ++i) {
const char* in = all_ports[i];
const char* out = jack_port_name( ports[ch] );
Reporter::reportEvent( 2, "Connecting", in, "to", out);
if (jack_connect(client, in, out)) {
throw Exception( __FILE__, __LINE__,
"Failed to jack_connect() ports", in, out);
}
// Found enough ports ?
if (++ch >= getChannel()) break;
}
free( all_ports );
}
/*------------------------------------------------------------------------------
* Open the audio source
*----------------------------------------------------------------------------*/
bool
JackDspSource :: open ( void ) throw ( Exception )
{
char client_name[255];
size_t rb_size;
unsigned int c;
if ( isOpen() ) {
return false;
}
// Register client with Jack
if ( jack_client_name != NULL ) {
snprintf(client_name, 255, "%s", jack_client_name);
} else {
snprintf(client_name, 255, "darkice-%d", getpid());
}
if ((client = jack_client_open(client_name, (jack_options_t)0, NULL)) == NULL) {
throw Exception( __FILE__, __LINE__, "JACK server not running?");
}
Reporter::reportEvent( 1, "Registering as JACK client", client_name);
// Check the sample rate is correct
if (jack_get_sample_rate( client ) != (jack_nframes_t)getSampleRate()) {
throw Exception( __FILE__, __LINE__,
"JACK server sample rate is different than "
"sample rate in darkice config file");
}
// Register ports with Jack
if (getChannel() == 1) {
if (!(ports[0] = jack_port_register(client,
"mono",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput,
0))) {
throw Exception( __FILE__, __LINE__,
"Cannot register input port", "mono");
}
} else if (getChannel() == 2) {
if (!(ports[0] = jack_port_register(client,
"left",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput,
0))) {
throw Exception( __FILE__, __LINE__,
"Cannot register input port", "left");
}
if (!(ports[1] = jack_port_register(client,
"right",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0))) {
throw Exception( __FILE__, __LINE__,
"Cannot register input port", "right");
}
} else {
throw Exception( __FILE__, __LINE__,
"Invalid number of channels", getChannel());
}
// Create a ring buffer for each channel
/* will take about 1 MB buffer for each channel */
rb_size = 5 /* number of seconds */
* jack_get_sample_rate(client) /* eg 48000 */
* sizeof (jack_default_audio_sample_t); /* eg 4 bytes */
for (c=0; c < getChannel(); c++) {
rb[c] = jack_ringbuffer_create(rb_size);
if (!rb[c]) {
throw Exception( __FILE__, __LINE__,
"Failed to create ringbuffer for", "channel", c);
}
}
// Set the callbacks
jack_on_shutdown(client, JackDspSource::shutdown_callback, (void*)this);
if (jack_set_process_callback(client,
JackDspSource::process_callback,
(void*)this)) {
throw Exception( __FILE__, __LINE__, "Failed to set process callback");
}
// Activate client
if (jack_activate(client)) {
throw Exception( __FILE__, __LINE__, "Can't activate client");
}
// Attempt to automatically connect up our input ports to something ?
if (auto_connect) {
do_auto_connect();
}
return true;
}
/*------------------------------------------------------------------------------
* Check whether read() would return anything
*----------------------------------------------------------------------------*/
bool
JackDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
const unsigned int max_wait_time = sec * 1000000;
const unsigned int wait_increment = 10000;
unsigned int cur_wait = 0;
if ( !isOpen() ) {
return false;
}
while (max_wait_time > cur_wait) {
bool canRead = true;
for (unsigned int c = 0 ; c < getChannel() ; c++) {
if (jack_ringbuffer_read_space(rb[c]) <= 0) {
canRead = false;
}
}
if (canRead) {
return true;
}
cur_wait += wait_increment;
usleep ( wait_increment );
}
usleep( usec );
for (unsigned int c = 0 ; c < getChannel() ; c++) {
if (jack_ringbuffer_read_space(rb[c]) <= 0) {
return false;
}
}
return true;
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
JackDspSource :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
jack_nframes_t samples = len / 2 / getChannel();
jack_nframes_t samples_read[2] = { 0, 0 };
short * output = (short*) buf;
unsigned int c, n;
if ( !isOpen() ) {
return 0;
}
// Ensure the temporary buffer is big enough
tmp_buffer = (jack_default_audio_sample_t*)realloc(tmp_buffer,
samples * sizeof( jack_default_audio_sample_t ) );
if (!tmp_buffer) {
throw Exception( __FILE__, __LINE__, "realloc on tmp_buffer failed");
}
// We must be sure to fetch as many data on both channels
int minBytesAvailable = samples * sizeof( jack_default_audio_sample_t );
for (c=0; c < getChannel(); c++) {
int readable = jack_ringbuffer_read_space(rb[c]);
if (readable < minBytesAvailable) {
minBytesAvailable = readable;
}
}
for (c=0; c < getChannel(); c++) {
// Copy frames from ring buffer to temporary buffer
// and then convert samples to output buffer
int bytes_read = jack_ringbuffer_read(rb[c],
(char*)tmp_buffer,
minBytesAvailable);
samples_read[c] = bytes_read / sizeof( jack_default_audio_sample_t );
// Convert samples from float to short and put in output buffer
for(n=0; n<samples_read[c]; n++) {
int tmp = lrintf(tmp_buffer[n] * 32768.0f);
if (tmp > SHRT_MAX) {
output[n*getChannel()+c] = SHRT_MAX;
} else if (tmp < SHRT_MIN) {
output[n*getChannel()+c] = SHRT_MIN;
} else {
output[n*getChannel()+c] = (short) tmp;
}
}
}
// Didn't get as many samples as we wanted ?
if (getChannel() == 2 && samples_read[0] != samples_read[1]) {
Reporter::reportEvent( 2,
"Warning: Read a different number of samples "
"for left and right channels");
}
// Return the number of bytes put in the output buffer
return samples_read[0] * 2 * getChannel();
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
JackDspSource :: close ( void ) throw ( Exception )
{
unsigned int i;
if ( !isOpen() ) {
return;
}
for(i = 0; i < getChannel(); i++) {
// Close the port for channel
if ( ports[i] ) {
jack_port_unregister( client, ports[i] );
ports[i] = NULL;
}
// Free up the ring buffer for channel
if ( rb[i] ) {
jack_ringbuffer_free( rb[i] );
rb[i] = NULL;
}
}
/* Leave the jack graph */
if (client) {
jack_client_close(client);
client = NULL;
}
}
/*------------------------------------------------------------------------------
* Callback called by JACK when audio is available
*
* Don't do anything too expensive here
* - just shove audio samples in ring buffer
*----------------------------------------------------------------------------*/
int
JackDspSource :: process_callback( jack_nframes_t nframes, void *arg )
{
JackDspSource* self = (JackDspSource*)arg;
size_t to_write = sizeof (jack_default_audio_sample_t) * nframes;
unsigned int c;
// Wait until it is ready
if (self->client == NULL) {
return 0;
}
/* copy data to ringbuffer; one per channel */
for (c=0; c < self->getChannel(); c++) {
/* check space */
size_t len;
if (jack_ringbuffer_write_space(self->rb[c]) < to_write) {
/* buffer is overflowing, skip the incoming data */
jack_ringbuffer_write_advance(self->rb[c], to_write);
/* prevent blocking the ring buffer by updating internal pointers
* jack will now not terminate on xruns
*/
Reporter::reportEvent( 1, "ring buffer full, skipping data");
/* We do not return error to jack callback handler and keep going */
} else {
/* buffer has space, put data into ringbuffer */
len = jack_ringbuffer_write(self->rb[c], (char *) jack_port_get_buffer(
self->ports[c], nframes), to_write);
if (len != to_write)
Reporter::reportEvent( 1, "failed to write to ring buffer (can not happen)");
}
}
// Success
return 0;
}
/*------------------------------------------------------------------------------
* Callback called when
*----------------------------------------------------------------------------*/
void
JackDspSource :: shutdown_callback( void *arg )
{
//JackDspSource* self = (JackDspSource*)arg;
Reporter::reportEvent( 1, "JackDspSource :: shutdown_callback");
}
#endif // SUPPORT_JACK_DSP

View File

@ -0,0 +1,284 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Copyright (c) 2005 Nicholas Humfrey. All rights reserved.
Tyrell DarkIce
File : JackDspSource.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef JACK_DSP_SOURCE_H
#define JACK_DSP_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Reporter.h"
#include "AudioSource.h"
#if defined( HAVE_JACK_LIB )
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#else
#error configure for JACK
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on JACK
*
* @author $Author$
* @version $Revision$
*/
class JackDspSource : public AudioSource, public virtual Reporter
{
private:
/**
* The jack client name.
*/
const char * jack_client_name;
/**
* The jack port
*/
jack_port_t * ports[2];
/**
* The jack ring buffer.
*/
jack_ringbuffer_t * rb[2];
/**
* The jack client.
*/
jack_client_t * client;
/**
* The jack audio sample buffer.
*/
jack_default_audio_sample_t * tmp_buffer;
/**
* Automatically connect the jack ports ? (default is to not)
*/
bool auto_connect;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
JackDspSource ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @exception Exception
*/
void
init ( const char* name ) throw ( Exception );
/**
* De-initialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
/**
* Attempt to connect up the JACK ports automatically
*/
void
do_auto_connect( ) throw ( Exception );
/**
* Callback called by JACK when audio is available
*/
static int
process_callback( jack_nframes_t nframes, void *arg );
/**
* Callback called by JACK when jackd is shutting down
*/
static void
shutdown_callback( void *arg );
public:
/**
* Constructor.
*
* @param name the name of the jack device
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channels number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
JackDspSource ( const char * name,
const char * jackClientName,
int sampleRate = 44100,
int bitsPerSample = 16,
int channels = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channels )
{
jack_client_name = jackClientName;
init( name );
}
/**
* Copy Constructor.
*
* @param jds the object to copy.
* @exception Exception
*/
inline
JackDspSource ( const JackDspSource & jds ) throw ( Exception )
: AudioSource( jds )
{
throw Exception( __FILE__, __LINE__, "JackDspSource doesn't copy");
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~JackDspSource ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual JackDspSource &
operator= ( const JackDspSource & ds ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__, "JackDspSource doesn't assign");
}
/**
* Open the JackDspSource.
* This does not put the Jack DSP device into recording mode.
* To start getting samples, call either canRead() or read().
*
* @return true if opening was successful, false otherwise
* @exception Exception
*
* @see #canRead
* @see #read
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the JackDspSource is registered
*
* @return true if Jack client is setup
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return client != NULL;
}
/**
* Check if the JackDspSource can be read from.
* Blocks until the specified time for data to be available.
* Puts the Jack DSP device into recording mode.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the JackDspSource is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the JackDspSource.
* Puts the Jack DSP device into recording mode.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the JackDspSource.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* JACK_DSP_SOURCE_H */

View File

@ -0,0 +1,396 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : LameLibEncoder.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// compile the whole file only if lame support configured in
#ifdef HAVE_LAME_LIB
#include "Exception.h"
#include "Util.h"
#include "LameLibEncoder.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Open an encoding session
*----------------------------------------------------------------------------*/
bool
LameLibEncoder :: open ( void )
throw ( Exception )
{
if ( isOpen() ) {
close();
}
// open the underlying sink
if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__,
"lame lib opening underlying sink error");
}
lameGlobalFlags = lame_init();
// ugly lame returns -1 in a pointer on allocation errors
// this is cast to (long int) so that the pointer can be handled
// on 64 bit systems as well
if ( !lameGlobalFlags || ((long int)lameGlobalFlags) == -1 ) {
throw Exception( __FILE__, __LINE__,
"lame lib init error",
(long int) lameGlobalFlags);
}
if ( 0 > lame_set_num_channels( lameGlobalFlags, getInChannel()) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting channels error",
getInChannel() );
}
if ( 0 > lame_set_mode( lameGlobalFlags,
getOutChannel() == 1 ? MONO : JOINT_STEREO) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting mode error",
JOINT_STEREO );
}
reportEvent( 5, "set lame mode", lame_get_mode( lameGlobalFlags));
reportEvent( 5,
"set lame channels",
lame_get_num_channels( lameGlobalFlags));
if ( 0 > lame_set_in_samplerate( lameGlobalFlags, getInSampleRate()) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting input sample rate error",
getInSampleRate() );
}
reportEvent( 5,
"set lame in sample rate",
lame_get_in_samplerate( lameGlobalFlags));
if ( 0 > lame_set_out_samplerate( lameGlobalFlags, getOutSampleRate()) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting output sample rate error",
getOutSampleRate() );
}
reportEvent( 5,
"set lame out sample rate",
lame_get_out_samplerate( lameGlobalFlags));
switch ( getOutBitrateMode() ) {
case cbr: {
if ( 0 > lame_set_brate( lameGlobalFlags, getOutBitrate()) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting output bit rate error",
getOutBitrate() );
}
reportEvent( 5,
"set lame bit rate",
lame_get_brate( lameGlobalFlags));
double d = (1.0 - getOutQuality()) * 10.0;
if ( d > 9 ) {
d = 9;
}
int q = int (d);
if ( 0 > lame_set_quality( lameGlobalFlags, q) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting quality error", q);
}
reportEvent( 5,
"set lame quality",
lame_get_quality( lameGlobalFlags));
} break;
case abr:
if ( 0 > lame_set_VBR( lameGlobalFlags,vbr_abr)) {
throw Exception( __FILE__, __LINE__,
"lame lib setting abr error", vbr_abr);
}
reportEvent( 5,
"set lame abr bitrate",
lame_get_VBR( lameGlobalFlags));
if ( 0 > lame_set_VBR_mean_bitrate_kbps( lameGlobalFlags,
getOutBitrate())) {
throw Exception( __FILE__, __LINE__,
"lame lib setting abr mean bitrate error",
getOutBitrate());
}
reportEvent( 5,
"set lame abr mean bitrate",
lame_get_VBR_mean_bitrate_kbps( lameGlobalFlags));
break;
case vbr: {
if ( 0 > lame_set_VBR( lameGlobalFlags, vbr_mtrh)) {
throw Exception( __FILE__, __LINE__,
"lame lib setting vbr error", vbr_mtrh );
}
reportEvent( 5,
"set lame vbr bitrate",
lame_get_VBR( lameGlobalFlags));
double d = (1.0 - getOutQuality()) * 10.0;
if ( d > 9 ) {
d = 9;
}
int q = int (d);
if ( 0 > lame_set_VBR_q( lameGlobalFlags, q) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting vbr quality error", q);
}
reportEvent( 5,
"set lame vbr quality",
lame_get_VBR_q( lameGlobalFlags));
} break;
}
if ( 0 > lame_set_lowpassfreq( lameGlobalFlags, lowpass) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting lowpass frequency error",
lowpass );
}
reportEvent( 5,
"set lame lowpass frequency",
lame_get_lowpassfreq( lameGlobalFlags));
if ( 0 > lame_set_highpassfreq( lameGlobalFlags, highpass) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting highpass frequency error",
lowpass );
}
reportEvent( 5,
"set lame highpass frequency",
lame_get_highpassfreq( lameGlobalFlags));
// not configurable lame settings
if ( 0 > lame_set_exp_nspsytune( lameGlobalFlags, 1) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting psycho acoustic model error");
}
reportEvent( 5,
"set lame psycho acoustic model",
lame_get_exp_nspsytune( lameGlobalFlags));
if ( 0 > lame_set_error_protection( lameGlobalFlags, 1) ) {
throw Exception( __FILE__, __LINE__,
"lame lib setting error protection error",
1 );
}
reportEvent( 5,
"set lame error protection",
lame_get_error_protection( lameGlobalFlags));
// let lame init its own params based on our settings
if ( 0 > lame_init_params( lameGlobalFlags) ) {
throw Exception( __FILE__, __LINE__,
"lame lib initializing params error" );
}
if (getReportVerbosity() >= 3) {
lame_print_config( lameGlobalFlags);
}
return true;
}
/*------------------------------------------------------------------------------
* Write data to the encoder
*----------------------------------------------------------------------------*/
unsigned int
LameLibEncoder :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
if ( !isOpen() || len == 0 ) {
return 0;
}
unsigned int bitsPerSample = getInBitsPerSample();
unsigned int inChannels = getInChannel();
unsigned int sampleSize = (bitsPerSample / 8) * inChannels;
unsigned char * b = (unsigned char*) buf;
unsigned int processed = len - (len % sampleSize);
unsigned int nSamples = processed / sampleSize;
short int * leftBuffer = new short int[nSamples];
short int * rightBuffer = new short int[nSamples];
if ( bitsPerSample == 8 ) {
Util::conv8( b, processed, leftBuffer, rightBuffer, inChannels);
} else if ( bitsPerSample == 16 ) {
Util::conv16( b,
processed,
leftBuffer,
rightBuffer,
inChannels,
isInBigEndian());
} else {
delete[] leftBuffer;
delete[] rightBuffer;
throw Exception( __FILE__, __LINE__,
"unsupported number of bits per sample for the encoder",
bitsPerSample );
}
// data chunk size estimate according to lame documentation
// NOTE: mp3Size is calculated based on the number of input channels
// which may be bigger than need, as output channels can be less
unsigned int mp3Size = (unsigned int) (1.25 * nSamples + 7200);
unsigned char * mp3Buf = new unsigned char[mp3Size];
int ret;
ret = lame_encode_buffer( lameGlobalFlags,
leftBuffer,
inChannels == 2 ? rightBuffer : leftBuffer,
nSamples,
mp3Buf,
mp3Size );
delete[] leftBuffer;
delete[] rightBuffer;
if ( ret < 0 ) {
reportEvent( 3, "lame encoding error", ret);
delete[] mp3Buf;
return 0;
}
unsigned int written = getSink()->write( mp3Buf, ret);
delete[] mp3Buf;
// just let go data that could not be written
if ( written < (unsigned int) ret ) {
reportEvent( 2,
"couldn't write all from encoder to underlying sink",
ret - written);
}
return processed;
}
/*------------------------------------------------------------------------------
* Flush the data from the encoder
*----------------------------------------------------------------------------*/
void
LameLibEncoder :: flush ( void )
throw ( Exception )
{
if ( !isOpen() ) {
return;
}
// data chunk size estimate according to lame documentation
unsigned int mp3Size = 7200;
unsigned char * mp3Buf = new unsigned char[mp3Size];
int ret;
ret = lame_encode_flush( lameGlobalFlags, mp3Buf, mp3Size );
unsigned int written = getSink()->write( mp3Buf, ret);
delete[] mp3Buf;
// just let go data that could not be written
if ( written < (unsigned int) ret ) {
reportEvent( 2,
"couldn't write all from encoder to underlying sink",
ret - written);
}
getSink()->flush();
}
/*------------------------------------------------------------------------------
* Close the encoding session
*----------------------------------------------------------------------------*/
void
LameLibEncoder :: close ( void ) throw ( Exception )
{
if ( isOpen() ) {
flush();
lame_close( lameGlobalFlags);
lameGlobalFlags = 0;
getSink()->close();
}
}
#endif // HAVE_LAME_LIB

View File

@ -0,0 +1,438 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : LameLibEncoder.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef LAME_LIB_ENCODER_H
#define LAME_LIB_ENCODER_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_LAME_LIB
#include <lame/lame.h>
#else
#error configure with lame
#endif
#include "Ref.h"
#include "Exception.h"
#include "Reporter.h"
#include "AudioEncoder.h"
#include "Sink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A class representing the lame encoder linked as a shared object or as
* a static library.
*
* @author $Author$
* @version $Revision$
*/
class LameLibEncoder : public AudioEncoder, public virtual Reporter
{
private:
/**
* Lame library global flags
*/
lame_global_flags * lameGlobalFlags;
/**
* Lowpass filter. Sound frequency in Hz, from where up the
* input is cut.
*/
int lowpass;
/**
* Highpass filter. Sound frequency in Hz, from where down the
* input is cut.
*/
int highpass;
/**
* Initialize the object.
*
* @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut.
* If 0, lame's default values are used,
* which depends on the out sample rate.
* @param highpass frequency threshold for the highpass filter.
* Input below this frequency is cut.
* If 0, lame's default values are used,
* which depends on the out sample rate.
* @exception Exception
*/
inline void
init ( int lowpass,
int highpass ) throw ( Exception )
{
this->lameGlobalFlags = NULL;
this->lowpass = lowpass;
this->highpass = highpass;
if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) {
throw Exception( __FILE__, __LINE__,
"specified bits per sample not supported",
getInBitsPerSample() );
}
if ( getInChannel() != 1 && getInChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of input channels for the encoder",
getInChannel() );
}
if ( getOutChannel() != 1 && getOutChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of output channels for the encoder",
getOutChannel() );
}
if ( getInChannel() < getOutChannel() ) {
throw Exception( __FILE__, __LINE__,
"output channels greater then input channels",
getOutChannel() );
}
}
/**
* De-initialize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
}
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
LameLibEncoder ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor.
*
* @param sink the sink to send mp3 output to
* @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input.
* @param inBigEndian shows if the input is big or little endian
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, inSampleRate is used.
* @param outChannel number of channels of the output.
* If 0, inChannel is used.
* @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut.
* If 0, lame's default values are used,
* which depends on the out sample rate.
* @param highpass frequency threshold for the highpass filter.
* Input below this frequency is cut.
* If 0, lame's default values are used,
* which depends on the out sample rate.
* @exception Exception
*/
inline
LameLibEncoder ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample,
unsigned int inChannel,
bool inBigEndian,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
int lowpass = 0,
int highpass = 0 )
throw ( Exception )
: AudioEncoder ( sink,
inSampleRate,
inBitsPerSample,
inChannel,
inBigEndian,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( lowpass, highpass);
}
/**
* Constructor.
*
* @param sink the sink to send mp3 output to
* @param as get input sample rate, bits per sample and channels
* from this AudioSource.
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, input sample rate is used.
* @param outChannel number of channels of the output.
* If 0, input channel is used.
* @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut.
* If 0, lame's default values are used,
* which depends on the out sample rate.
* @param highpass frequency threshold for the highpass filter.
* Input below this frequency is cut.
* If 0, lame's default values are used,
* which depends on the out sample rate.
* @exception Exception
*/
inline
LameLibEncoder ( Sink * sink,
const AudioSource * as,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
int lowpass = 0,
int highpass = 0 )
throw ( Exception )
: AudioEncoder ( sink,
as,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( lowpass, highpass);
}
/**
* Copy constructor.
*
* @param encoder the LameLibEncoder to copy.
*/
inline
LameLibEncoder ( const LameLibEncoder & encoder )
throw ( Exception )
: AudioEncoder( encoder )
{
init( encoder.lowpass, encoder.highpass );
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~LameLibEncoder ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
strip();
}
/**
* Assignment operator.
*
* @param encoder the LameLibEncoder to assign this to.
* @return a reference to this LameLibEncoder.
* @exception Exception
*/
inline virtual LameLibEncoder &
operator= ( const LameLibEncoder & encoder ) throw ( Exception )
{
if ( this != &encoder ) {
strip();
AudioEncoder::operator=( encoder);
init( encoder.lowpass, encoder.highpass );
}
return *this;
}
/**
* Get the version string of the underlying lame library.
*
* @return the version string of the underlying lame library.
*/
inline const char *
getLameVersion( void )
{
return get_lame_version();
}
/**
* Check whether encoding is in progress.
*
* @return true if encoding is in progress, false otherwise.
*/
inline virtual bool
isRunning ( void ) const throw ()
{
return isOpen();
}
/**
* Start encoding. This function returns as soon as possible,
* with encoding started in the background.
*
* @return true if encoding has started, false otherwise.
* @exception Exception
*/
inline virtual bool
start ( void ) throw ( Exception )
{
return open();
}
/**
* Stop encoding. Stops the encoding running in the background.
*
* @exception Exception
*/
inline virtual void
stop ( void ) throw ( Exception )
{
return close();
}
/**
* Open an encoding session.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the encoding session is open.
*
* @return true if the encoding session is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return lameGlobalFlags != 0;
}
/**
* Check if the encoder is ready to accept data.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the encoder is ready to accept data,
* false otherwise.
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
if ( !isOpen() ) {
return false;
}
return true;
}
/**
* Write data to the encoder.
* Buf is expected to be a sequence of big-endian 16 bit values,
* with left and right channels interleaved. Len is the number of
* bytes, must be a multiple of 4.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* Flush all data that was written to the encoder to the underlying
* connection.
*
* @exception Exception
*/
virtual void
flush ( void ) throw ( Exception );
/**
* Close the encoding session.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* LAME_LIB_ENCODER_H */

View File

@ -0,0 +1,113 @@
bin_PROGRAMS = darkice
darkice_CXXFLAGS = \
-O2 -pedantic -Wall \
$(DEBUG_CXXFLAGS) \
$(PTHREAD_CFLAGS) \
$(LAME_CFLAGS) \
$(VORBIS_CFLAGS) \
$(OPUS_CFLAGS) \
$(FAAC_CFLAGS) \
$(AACPLUS_CFLAGS) \
$(TWOLAME_CFLAGS) \
$(ALSA_CFLAGS) \
$(PULSEAUDIO_CFLAGS) \
$(JACK_CFLAGS) \
$(SRC_CFLAGS)
darkice_LDADD = \
$(PTHREAD_LIBS) \
$(LAME_LIBS) \
$(VORBIS_LIBS) \
$(OPUS_LIBS) \
$(FAAC_LIBS) \
$(AACPLUS_LIBS) \
$(TWOLAME_LIBS) \
$(ALSA_LIBS) \
$(PULSEAUDIO_LIBS) \
$(JACK_LIBS) \
$(SRC_LIBS)
if HAVE_SRC_LIB
AFLIB_SOURCE =
else
AFLIB_SOURCE = aflibDebug.h\
aflibDebug.cc\
aflibConverter.h\
aflibConverter.cc\
aflibConverterLargeFilter.h\
aflibConverterSmallFilter.h
endif
darkice_SOURCES = AudioEncoder.h\
AudioSource.h\
AudioSource.cpp\
BufferedSink.cpp\
BufferedSink.h\
CastSink.cpp\
CastSink.h\
FileSink.h\
FileSink.cpp\
Connector.cpp\
Connector.h\
MultiThreadedConnector.cpp\
MultiThreadedConnector.h\
DarkIce.cpp\
DarkIce.h\
Exception.cpp\
Exception.h\
IceCast.cpp\
IceCast.h\
IceCast2.cpp\
IceCast2.h\
ShoutCast.cpp\
ShoutCast.h\
FileCast.h\
FileCast.cpp\
LameLibEncoder.cpp\
LameLibEncoder.h\
TwoLameLibEncoder.cpp\
TwoLameLibEncoder.h\
VorbisLibEncoder.cpp\
VorbisLibEncoder.h\
OpusLibEncoder.cpp\
OpusLibEncoder.h\
FaacEncoder.cpp\
FaacEncoder.h\
aacPlusEncoder.cpp\
aacPlusEncoder.h\
OssDspSource.cpp\
OssDspSource.h\
SerialUlaw.cpp\
SerialUlaw.h\
SolarisDspSource.cpp\
SolarisDspSource.h\
Ref.h\
Referable.h\
Sink.h\
Source.h\
TcpSocket.cpp\
TcpSocket.h\
Util.cpp\
Util.h\
ConfigSection.h\
ConfigSection.cpp\
DarkIceConfig.h\
DarkIceConfig.cpp\
Reporter.h\
Reporter.cpp\
AlsaDspSource.h\
AlsaDspSource.cpp\
PulseAudioDspSource.h\
PulseAudioDspSource.cpp\
JackDspSource.h\
JackDspSource.cpp\
main.cpp \
$(AFLIB_SOURCE)
EXTRA_darkice_SOURCES = aflibDebug.h\
aflibDebug.cc\
aflibConverter.h\
aflibConverter.cc\
aflibConverterLargeFilter.h\
aflibConverterSmallFilter.h

View File

@ -0,0 +1,429 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : MultiThreadedConnector.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#include "Exception.h"
#include "MultiThreadedConnector.h"
#include "Util.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
MultiThreadedConnector :: init ( bool reconnect ) throw ( Exception )
{
this->reconnect = reconnect;
pthread_mutex_init( &mutexProduce, 0);
pthread_cond_init( &condProduce, 0);
threads = 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
MultiThreadedConnector :: strip ( void ) throw ( Exception )
{
if ( threads ) {
delete[] threads;
threads = 0;
}
pthread_cond_destroy( &condProduce);
pthread_mutex_destroy( &mutexProduce);
}
/*------------------------------------------------------------------------------
* Constructor
*----------------------------------------------------------------------------*/
MultiThreadedConnector :: MultiThreadedConnector (
const MultiThreadedConnector & connector )
throw ( Exception )
: Connector( connector)
{
reconnect = connector.reconnect;
mutexProduce = connector.mutexProduce;
condProduce = connector.condProduce;
if ( threads ) {
delete[] threads;
}
threads = new ThreadData[numSinks];
for ( unsigned int i = 0; i < numSinks; ++i ) {
threads[i] = connector.threads[i];
}
}
/*------------------------------------------------------------------------------
* Assignment operator
*----------------------------------------------------------------------------*/
MultiThreadedConnector &
MultiThreadedConnector :: operator= ( const MultiThreadedConnector & connector )
throw ( Exception )
{
if ( this != &connector ) {
Connector::operator=( connector);
reconnect = connector.reconnect;
mutexProduce = connector.mutexProduce;
condProduce = connector.condProduce;
if ( threads ) {
delete[] threads;
}
threads = new ThreadData[numSinks];
for ( unsigned int i = 0; i < numSinks; ++i ) {
threads[i] = connector.threads[i];
}
}
return *this;
}
/*------------------------------------------------------------------------------
* Open the source and all the sinks if needed
* Create the sink threads
*----------------------------------------------------------------------------*/
bool
MultiThreadedConnector :: open ( void ) throw ( Exception )
{
unsigned int i;
size_t st;
if ( !Connector::open() ) {
return false;
}
running = true;
pthread_attr_init( &threadAttr);
pthread_attr_getstacksize(&threadAttr, &st);
if (st < 128 * 1024) {
reportEvent( 5, "MultiThreadedConnector :: open, stack size ",
(long)st);
st = 128 * 1024;
pthread_attr_setstacksize(&threadAttr, st);
}
pthread_attr_setdetachstate( &threadAttr, PTHREAD_CREATE_JOINABLE);
threads = new ThreadData[numSinks];
for ( i = 0; i < numSinks; ++i ) {
ThreadData * threadData = threads + i;
threadData->connector = this;
threadData->ixSink = i;
threadData->accepting = true;
threadData->isDone = true;
if ( pthread_create( &(threadData->thread),
&threadAttr,
ThreadData::threadFunction,
threadData ) ) {
break;
}
}
// if could not create all, delete the ones created
if ( i < numSinks ) {
unsigned int j;
// signal to stop for all running threads
pthread_mutex_lock( &mutexProduce);
running = false;
pthread_cond_broadcast( &condProduce);
pthread_mutex_unlock( &mutexProduce);
for ( j = 0; j < i; ++j ) {
pthread_join( threads[j].thread, 0);
}
delete[] threads;
threads = 0;
return false;
}
return true;
}
/*------------------------------------------------------------------------------
* Transfer some data from the source to the sink
*----------------------------------------------------------------------------*/
unsigned int
MultiThreadedConnector :: transfer ( unsigned long bytes,
unsigned int bufSize,
unsigned int sec,
unsigned int usec )
throw ( Exception )
{
unsigned int b;
if ( numSinks == 0 ) {
return 0;
}
if ( bufSize == 0 ) {
return 0;
}
dataBuffer = new unsigned char[bufSize];
dataSize = 0;
reportEvent( 6, "MultiThreadedConnector :: transfer, bytes", bytes);
for ( b = 0; !bytes || b < bytes; ) {
if ( source->canRead( sec, usec) ) {
unsigned int i;
pthread_mutex_lock( &mutexProduce);
dataSize = source->read( dataBuffer, bufSize);
b += dataSize;
// check for EOF
if ( dataSize == 0 ) {
reportEvent( 3, "MultiThreadedConnector :: transfer, EOF");
pthread_mutex_unlock( &mutexProduce);
break;
}
for ( i = 0; i < numSinks; ++i ) {
threads[i].isDone = false;
}
// tell sink threads that there is some data available
pthread_cond_broadcast( &condProduce);
// wait for all sink threads to get done with this data
while ( true ) {
for ( i = 0; i < numSinks && threads[i].isDone; ++i );
if ( i == numSinks ) {
break;
}
pthread_cond_wait( &condProduce, &mutexProduce);
}
pthread_mutex_unlock( &mutexProduce);
} else {
reportEvent( 3, "MultiThreadedConnector :: transfer, can't read");
break;
}
}
delete[] dataBuffer;
return b;
}
/*------------------------------------------------------------------------------
* The function for each thread.
* Read the presented data
*----------------------------------------------------------------------------*/
void
MultiThreadedConnector :: sinkThread( int ixSink )
{
ThreadData * threadData = &threads[ixSink];
Sink * sink = sinks[ixSink].get();
while ( running ) {
// wait for some data to become available
pthread_mutex_lock( &mutexProduce);
while ( running && threadData->isDone ) {
pthread_cond_wait( &condProduce, &mutexProduce);
}
if ( !running ) {
pthread_mutex_unlock( &mutexProduce);
break;
}
if ( threadData->cut) {
sink->cut();
threadData->cut = false;
}
if ( threadData->accepting ) {
if ( sink->canWrite( 0, 0) ) {
try {
sink->write( dataBuffer, dataSize);
} catch ( Exception & e ) {
// something wrong. don't accept more data, try to
// reopen the sink next time around
threadData->accepting = false;
}
} else {
reportEvent( 4,
"MultiThreadedConnector :: sinkThread can't write ",
ixSink);
// don't care if we can't write
}
}
threadData->isDone = true;
pthread_cond_broadcast( &condProduce);
pthread_mutex_unlock( &mutexProduce);
if ( !threadData->accepting ) {
if ( reconnect ) {
reportEvent( 4,
"MultiThreadedConnector :: sinkThread reconnecting ",
ixSink);
// if we're not accepting, try to reopen the sink
try {
sink->close();
Util::sleep(1L, 0L);
sink->open();
sched_yield();
threadData->accepting = sink->isOpen();
} catch ( Exception & e ) {
// don't care, just try and try again
}
} else {
// if !reconnect, just stop the connector
running = false;
}
}
}
}
/*------------------------------------------------------------------------------
* Signal to each sink to cut what they've done so far, and start anew.
*----------------------------------------------------------------------------*/
void
MultiThreadedConnector :: cut ( void ) throw ()
{
for ( unsigned int i = 0; i < numSinks; ++i ) {
threads[i].cut = true;
}
// TODO: it might be more appropriate to signal all the threads here
// but, they'll get signaled on new data anyway, and it might be
// enough for them to cut at that time
}
/*------------------------------------------------------------------------------
* Stop the treads
* Close the source and all the sinks if needed
*----------------------------------------------------------------------------*/
void
MultiThreadedConnector :: close ( void ) throw ( Exception )
{
unsigned int i;
// signal to stop for all threads
pthread_mutex_lock( &mutexProduce);
running = false;
pthread_cond_broadcast( &condProduce);
pthread_mutex_unlock( &mutexProduce);
// wait for all the threads to finish
for ( i = 0; i < numSinks; ++i ) {
pthread_join( threads[i].thread, 0);
}
pthread_attr_destroy( &threadAttr);
Connector::close();
}
/*------------------------------------------------------------------------------
* The thread function
*----------------------------------------------------------------------------*/
void *
MultiThreadedConnector :: ThreadData :: threadFunction( void * param )
{
struct sched_param sched;
int sched_type;
ThreadData * threadData = (ThreadData*) param;
pthread_getschedparam( threadData->thread, &sched_type, &sched );
reportEvent( 5,
"MultiThreadedConnector :: ThreadData :: threadFunction, "
"was (thread, priority, type): ",
param,
sched.sched_priority,
sched_type == SCHED_FIFO ? "SCHED_FIFO" :
sched_type == SCHED_RR ? "SCHED_RR" :
sched_type == SCHED_OTHER ? "SCHED_OTHER" :
"INVALID"
);
sched.sched_priority = 1;
pthread_setschedparam( threadData->thread, SCHED_FIFO, &sched);
pthread_getschedparam( threadData->thread, &sched_type, &sched );
reportEvent( 5,
"MultiThreadedConnector :: ThreadData :: threadFunction, "
"now is (thread, priority, type): ",
param,
sched.sched_priority,
sched_type == SCHED_FIFO ? "SCHED_FIFO" :
sched_type == SCHED_RR ? "SCHED_RR" :
sched_type == SCHED_OTHER ? "SCHED_OTHER" :
"INVALID"
);
threadData->connector->sinkThread( threadData->ixSink);
return 0;
}

View File

@ -0,0 +1,359 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : MultiThreadedConnector.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef MULTI_THREADED_CONNECTOR_H
#define MULTI_THREADED_CONNECTOR_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// check for __NetBSD__ because it won't be found by AC_CHECK_HEADER on NetBSD
// as pthread.h is in /usr/pkg/include, not /usr/include
#if defined( HAVE_PTHREAD_H ) || defined( __NetBSD__ )
#include <pthread.h>
#else
#error need pthread.h
#endif
#include "Referable.h"
#include "Ref.h"
#include "Reporter.h"
#include "Source.h"
#include "Sink.h"
#include "Connector.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Connects a source to one or more sinks, using a multi-threaded
* producer - consumer approach.
*
* @author $Author$
* @version $Revision$
*/
class MultiThreadedConnector : public virtual Connector
{
private:
/**
* Helper class to collect information for starting threads.
*/
class ThreadData
{
public:
/**
* The connector starting the thread
*/
MultiThreadedConnector * connector;
/**
* The index of the sink this thread writes to.
*/
unsigned int ixSink;
/**
* The POSIX thread itself.
*/
pthread_t thread;
/**
* Marks if the thread is accepting data.
*/
bool accepting;
/**
* Marks if the thread has processed the last batch
* of data.
*/
bool isDone;
/**
* A flag to show that the sink should be made to cut in the
* next iteration.
*/
bool cut;
/**
* Default constructor.
*/
inline
ThreadData()
{
this->connector = 0;
this->ixSink = 0;
this->thread = 0;
this->accepting = false;
this->isDone = false;
this->cut = false;
}
/**
* The thread function.
*
* @param param thread parameter, a pointer to a
* ThreadData
* @return nothing
*/
static void *
threadFunction( void * param );
};
/**
* The mutex of this object.
*/
pthread_mutex_t mutexProduce;
/**
* The conditional variable for presenting new data.
*/
pthread_cond_t condProduce;
/**
* The thread attributes.
*/
pthread_attr_t threadAttr;
/**
* The threads for the sinks.
*/
ThreadData * threads;
/**
* Signal if we're running or not, so the threads no if to stop.
*/
bool running;
/**
* Flag to show if the connector should try to reconnect if
* the connection is dropped on the other side.
*/
bool reconnect;
/**
* The buffer of information presented to each thread.
*/
unsigned char * dataBuffer;
/**
* The amount of information presented to each thread.
*/
unsigned int dataSize;
/**
* Initialize the object.
*
* @param reconnect flag to indicate if the connector should
* try to reconnect if the connection was
* dropped by the other end
* @exception Exception
*/
void
init ( bool reconnect ) throw ( Exception );
/**
* De-initialize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
MultiThreadedConnector ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor based on a Source.
*
* @param source the source to connect to the sinks.
* @param reconnect flag to indicate if the connector should
* try to reconnect if the connection was
* dropped by the other end
* @exception Exception
*/
inline
MultiThreadedConnector ( Source * source,
bool reconnect )
throw ( Exception )
: Connector( source )
{
init(reconnect);
}
/**
* Constructor based on a Source and a Sink.
*
* @param source the source to connect to the sinks.
* @param sink a sink to connect to the source.
* @param reconnect flag to indicate if the connector should
* try to reconnect if the connection was
* dropped by the other end
* @exception Exception
*/
inline
MultiThreadedConnector ( Source * source,
Sink * sink,
bool reconnect )
throw ( Exception )
: Connector( source, sink)
{
init(reconnect);
}
/**
* Copy constructor.
*
* @param connector the object to copy.
* @exception Exception
*/
MultiThreadedConnector ( const MultiThreadedConnector & connector )
throw ( Exception );
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~MultiThreadedConnector( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param connector the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
virtual MultiThreadedConnector &
operator= ( const MultiThreadedConnector & connector )
throw ( Exception );
/**
* Open the connector. Opens the Source and the Sinks if necessary.
*
* @return true if opening was successful, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Transfer a given amount of data from the Source to all the
* Sinks attached.
* If an attached Sink closes or encounteres an error during the
* process, it is detached and the function carries on with the
* rest of the Sinks. If no Sinks remain, or an error is encountered
* with the Source, the function returns prematurely.
*
* @param bytes the amount of data to transfer, in bytes.
* If 0, transfer forever.
* @param bufSize the size of the buffer to use for transfering.
* This amount of data is read from the Source and
* written to each Sink on each turn.
* @param sec the number of seconds to wait for the Source to have
* data available in each turn, and the number of seconds
* to wait for the Sinks to accept data.
* @param usec the number of micros seconds to wait for the Source to
* have data available in each turn, and the number of
* micro seconds to wait for the Sinks to accept data.
* @return the number of bytes read from the Source.
* @exception Exception
*/
virtual unsigned int
transfer ( unsigned long bytes,
unsigned int bufSize,
unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Signal to each sink we have that they need to cut what they are
* doing, and start again. For FileSinks, this usually means to
* save the archive file recorded so far, and start a new archive
* file.
*/
virtual void
cut ( void ) throw ();
/**
* Close the Connector. The Source and all Sinks are closed.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
/**
* This is the worker function for each thread.
* This function has to return fast
*
* @param ixSink the index of the sink this thread works on.
*/
void
sinkThread( int ixSink );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* MULTI_THREADED_CONNECTOR_H */

View File

@ -0,0 +1,572 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : OpusLibEncoder.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// compile only if configured for Ogg / Opus
#ifdef HAVE_OPUS_LIB
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "Exception.h"
#include "Util.h"
#include "OpusLibEncoder.h"
#include "CastSink.h"
#include <cstring>
#include <cstdlib>
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the encoder
*----------------------------------------------------------------------------*/
void
OpusLibEncoder :: init ( unsigned int outMaxBitrate )
throw ( Exception )
{
this->outMaxBitrate = outMaxBitrate;
if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) {
throw Exception( __FILE__, __LINE__,
"specified bits per sample not supported",
getInBitsPerSample() );
}
if ( getInChannel() != 1 && getInChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of channels for the encoder",
getInChannel() );
}
if ( getOutSampleRate() != 48000 ) {
throw Exception( __FILE__, __LINE__,
"unsupported sample rate for this encoder, you should resample your input to 48000Hz",
getOutSampleRate() );
}
if ( getOutSampleRate() == getInSampleRate() ) {
resampleRatio = 1;
converter = 0;
} else {
resampleRatio = ( (double) getOutSampleRate() /
(double) getInSampleRate() );
// Determine if we can use linear interpolation.
// The inverse of the ratio must be a power of two for linear mode to
// be of sufficient quality.
bool useLinear = true;
double inverse = 1 / resampleRatio;
int integer = (int) inverse;
// Check that the inverse of the ratio is an integer
if( integer == inverse ) {
while( useLinear && integer ) { // Loop through the bits
// If the lowest order bit is not the only one set
if( integer & 1 && integer != 1 ) {
// Not a power of two; cannot use linear
useLinear = false;
} else {
// Shift all the bits over and try again
integer >>= 1;
}
}
} else {
useLinear = false;
}
// If we get here and useLinear is still true, then we have
// a power of two.
// open the aflibConverter in
// - high quality
// - linear or quadratic (non-linear) based on algorithm
// - not filter interpolation
#ifdef HAVE_SRC_LIB
int srcError = 0;
converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST,
getInChannel(), &srcError);
if(srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
#else
converter = new aflibConverter( true, useLinear, false);
#endif
}
encoderOpen = false;
}
/*------------------------------------------------------------------------------
* Open an encoding session
*----------------------------------------------------------------------------*/
bool
OpusLibEncoder :: open ( void )
throw ( Exception )
{
int ret;
if ( isOpen() ) {
close();
}
// open the underlying sink
if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__,
"opus lib opening underlying sink error");
}
int bufferSize = (getInBitsPerSample()/8) * getInChannel() * 480;
internalBuffer = new unsigned char[bufferSize];
internalBufferLength = 0;
memset( internalBuffer, 0, bufferSize);
int err;
opusEncoder = opus_encoder_create( getOutSampleRate(),
getInChannel(),
OPUS_APPLICATION_AUDIO,
&err);
if( err != OPUS_OK ) {
throw Exception( __FILE__, __LINE__,
"opus encoder creation error",
err);
}
opus_encoder_ctl(opusEncoder, OPUS_SET_COMPLEXITY(10));
opus_encoder_ctl(opusEncoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC));
switch ( getOutBitrateMode() ) {
case cbr: {
int maxBitrate = getOutBitrate() * 1000;
if ( !maxBitrate ) {
maxBitrate = 96000;
}
opus_encoder_ctl(opusEncoder, OPUS_SET_BITRATE(maxBitrate));
opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(0));
} break;
case abr: {
int maxBitrate = getOutBitrate() * 1000;
if ( !maxBitrate ) {
maxBitrate = 96000;
}
/* set non-managed VBR around the average bitrate */
opus_encoder_ctl(opusEncoder, OPUS_SET_BITRATE(maxBitrate));
opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(1));
opus_encoder_ctl(opusEncoder, OPUS_SET_VBR_CONSTRAINT(1));
} break;
case vbr:
int maxBitrate = getOutBitrate() * 1000;
if ( !maxBitrate ) {
maxBitrate = 96000;
}
/* set non-managed VBR around the average bitrate */
opus_encoder_ctl(opusEncoder, OPUS_SET_BITRATE(maxBitrate));
opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(1));
opus_encoder_ctl(opusEncoder, OPUS_SET_VBR_CONSTRAINT(0));
break;
}
if ( (ret = ogg_stream_init( &oggStreamState, 0)) ) {
throw Exception( __FILE__, __LINE__, "ogg stream init error", ret);
}
// First, we need to assemble and send a OggOpus header.
OpusIdHeader header;
strncpy(header.magic, "OpusHead", 8);
header.version = 1;
header.channels = getOutChannel();
header.preskip = 0;
header.samplerate = getInSampleRate();
header.gain = 0; // technically a fixed-point decimal.
header.chanmap = 0;
// And, now we need to send a Opus comment header.
// Anything after this can be audio.
char vendor[8] = "darkice";
char titlestr[7] = "TITLE=";
OpusCommentHeader::Tags tags[1];
char name[40];
CastSink* sink = dynamic_cast<CastSink*>(getSink().get());
if( sink && sink->getName() ) {
strncpy(name, (char*)sink->getName(), 39);
name[39] = 0;
}
else {
strncpy(name, "Darkice Stream", 39);
}
tags[0].tag_len = strlen(titlestr) + strlen(name);
tags[0].tag_str = (char*) malloc( tags[0].tag_len + 1 );
if( tags[0].tag_str == NULL ) {
throw Exception( __FILE__, __LINE__, "malloc failed");
}
strncpy( tags[0].tag_str, titlestr, tags[0].tag_len);
strncat( tags[0].tag_str, name, tags[0].tag_len);
OpusCommentHeader commentHeader;
strncpy(commentHeader.magic, "OpusTags", 8);
commentHeader.vendor_length = strlen(vendor);
commentHeader.vendor_string = vendor;
commentHeader.num_tags = 1;
commentHeader.tags = tags;
ogg_packet oggHeader;
ogg_packet oggCommentHeader;
memset(&oggHeader, 0, sizeof(oggHeader));
memset(&oggCommentHeader, 0, sizeof(oggCommentHeader));
unsigned char* headerData = NULL;
unsigned char* commentData = NULL;
int headerLen = 0;
int commentLen = 0;
headerLen = header.buildPacket( &headerData);
commentLen = commentHeader.buildPacket( &commentData);
oggHeader.packet = headerData;
oggHeader.bytes = headerLen;
oggHeader.b_o_s = 1;
oggHeader.e_o_s = 0;
oggHeader.granulepos = 0;
oggHeader.packetno = 0;
oggCommentHeader.packet = commentData;
oggCommentHeader.bytes = commentLen;
oggCommentHeader.b_o_s = 0;
oggCommentHeader.e_o_s = 0;
oggCommentHeader.granulepos = 0;
oggCommentHeader.packetno = 1;
oggPacketNumber = 2;
oggGranulePosition = 0;
ogg_stream_packetin( &oggStreamState, &oggHeader);
ogg_stream_packetin( &oggStreamState, &oggCommentHeader);
ogg_page oggPage;
while ( ogg_stream_flush( &oggStreamState, &oggPage) ) {
getSink()->write( oggPage.header, oggPage.header_len);
getSink()->write( oggPage.body, oggPage.body_len);
}
free(tags[0].tag_str);
free(headerData);
free(commentData);
// initialize the resampling coverter if needed
if ( converter ) {
#ifdef HAVE_SRC_LIB
converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel());
converterData.data_in = new float[converterData.input_frames*getInChannel()];
converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1);
converterData.data_out = new float[getInChannel() * converterData.output_frames];
converterData.src_ratio = resampleRatio;
converterData.end_of_input = 0;
#else
converter->initialize( resampleRatio, getInChannel());
#endif
}
encoderOpen = true;
reconnectError = false;
return true;
}
/*------------------------------------------------------------------------------
* Write data to the encoder
*----------------------------------------------------------------------------*/
unsigned int
OpusLibEncoder :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
if ( !isOpen() || len == 0 ) {
return 0;
}
unsigned int channels = getInChannel();
unsigned int bitsPerSample = getInBitsPerSample();
unsigned int sampleSize = (bitsPerSample / 8) * channels;
unsigned int i;
if ( getInChannel() == 2 && getOutChannel() == 1 ) {
for ( i = 0; i < len/sampleSize; i++) {
if ( bitsPerSample == 8 ) {
char * buf8 = (char *) buf;
unsigned int ix = sampleSize * i;
unsigned int iix = ix;
buf8[i] = (buf8[ix] + buf8[++iix]) / 2;
}
if ( bitsPerSample == 16 ) {
short * buf16 = (short *) buf;
unsigned int ix = (bitsPerSample >> 3) * i;
unsigned int iix = ix;
buf16[i] = (buf16[ix] + buf16[++iix]) / 2;
}
}
len >>= 1;
channels = 1;
}
sampleSize = (bitsPerSample / 8) * channels;
unsigned int processed = 0;
unsigned int bytesToProcess = len - (len % sampleSize);
unsigned int totalProcessed = 0;
unsigned char * b = (unsigned char*) buf;
unsigned char * tempBuffer = NULL;
if( internalBufferLength > 0 ) {
tempBuffer = new unsigned char[len + internalBufferLength];
memset( tempBuffer, 0, len + internalBufferLength);
if( !tempBuffer ) {
throw Exception( __FILE__, __LINE__, "could not allocate temp buffer");
}
memcpy( tempBuffer, internalBuffer, internalBufferLength);
memcpy( tempBuffer+internalBufferLength, buf, len);
b = tempBuffer;
bytesToProcess += internalBufferLength;
}
while ( bytesToProcess / resampleRatio >= 480 * sampleSize ) {
unsigned int toProcess = bytesToProcess / (resampleRatio * sampleSize);
if( toProcess >= 480 / resampleRatio) {
processed = 480 / resampleRatio;
}
int opusBufferSize = (1275*3+7)*channels;
unsigned char* opusBuffer = new unsigned char[opusBufferSize];
// convert the byte-based raw input into a short buffer
// with channels still interleaved
unsigned int totalSamples = processed * channels;
short int * shortBuffer = new short int[totalSamples];
Util::conv( bitsPerSample, b, processed*sampleSize, shortBuffer, isInBigEndian());
if ( converter && processed > 0 ) {
// resample if needed
int inCount = processed;
int outCount = 480; //(int) (inCount * resampleRatio);
short int * resampledBuffer = new short int[(outCount+1)* channels];
int converted;
#ifdef HAVE_SRC_LIB
(void)inCount;
converterData.input_frames = processed;
src_short_to_float_array (shortBuffer, converterData.data_in, totalSamples);
int srcError = src_process (converter, &converterData);
if (srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
converted = converterData.output_frames_gen;
src_float_to_short_array(converterData.data_out, resampledBuffer, converted*channels);
#else
converted = converter->resample( inCount,
outCount,
shortBuffer,
resampledBuffer );
#endif
if( converted != 480) {
throw Exception( __FILE__, __LINE__, "resampler error: expected 480 samples", converted);
}
int encBytes = opus_encode( opusEncoder, resampledBuffer, 480, opusBuffer, opusBufferSize);
if( encBytes == -1 ) {
throw Exception( __FILE__, __LINE__, "opus encoder error");
}
oggGranulePosition += converted;
opusBlocksOut( encBytes, opusBuffer);
delete[] resampledBuffer;
} else if( processed > 0) {
memset( opusBuffer, 0, opusBufferSize);
int encBytes = opus_encode( opusEncoder, shortBuffer, processed, opusBuffer, opusBufferSize);
if( encBytes == -1 ) {
throw Exception( __FILE__, __LINE__, "opus encoder error");
}
oggGranulePosition += processed;
opusBlocksOut( encBytes, opusBuffer);
}
delete[] shortBuffer;
delete[] opusBuffer;
bytesToProcess -= processed * sampleSize;
totalProcessed += processed * sampleSize;
b = ((unsigned char*)b) + (processed * sampleSize);
}
int newLen = len - (len % sampleSize) + internalBufferLength - totalProcessed;
newLen -= newLen % sampleSize;
if( newLen > 0 ) {
memcpy( internalBuffer, b, newLen);
totalProcessed += newLen;
internalBufferLength = newLen;
} else {
internalBufferLength = 0;
}
if( tempBuffer ) {
delete[] tempBuffer;
tempBuffer = NULL;
}
return totalProcessed;
}
/*------------------------------------------------------------------------------
* Flush the data from the encoder
*----------------------------------------------------------------------------*/
void
OpusLibEncoder :: flush ( void )
throw ( Exception )
{
if ( !isOpen() || reconnectError == true ) {
return;
}
int opusBufferSize = (1275*3+7)*getOutChannel();
unsigned char * opusBuffer = new unsigned char[opusBufferSize];
short int * shortBuffer = new short int[480*getInChannel()];
// Send an empty audio packet along to flush out the stream.
memset( shortBuffer, 0, 480*getInChannel()*sizeof(*shortBuffer));
memset( opusBuffer, 0, opusBufferSize);
int encBytes = opus_encode( opusEncoder, shortBuffer, 480, opusBuffer, opusBufferSize);
if( encBytes == -1 ) {
throw Exception( __FILE__, __LINE__, "opus encoder error");
}
oggGranulePosition += 480;
// Send the empty block to the Ogg layer, and mark the
// EOS flag. This will trigger any remaining packets to be
// sent.
opusBlocksOut( encBytes, opusBuffer, true);
delete[] opusBuffer;
delete[] shortBuffer;
getSink()->flush();
}
/*------------------------------------------------------------------------------
* Send pending Opus blocks to the underlying stream
*----------------------------------------------------------------------------*/
void
OpusLibEncoder :: opusBlocksOut ( int bytes,
unsigned char* data,
bool eos ) throw ( Exception )
{
ogg_packet oggPacket;
ogg_page oggPage;
oggPacket.packet = data;
oggPacket.bytes = bytes;
oggPacket.b_o_s = 0;
oggPacket.e_o_s = ( eos ) ? 1 : 0;
oggPacket.granulepos = oggGranulePosition;
oggPacket.packetno = oggPacketNumber;
oggPacketNumber++;
if( ogg_stream_packetin( &oggStreamState, &oggPacket) == 0) {
while( ogg_stream_pageout( &oggStreamState, &oggPage) ||
( eos && ogg_stream_flush( &oggStreamState, &oggPage) ) ) {
int written;
written = getSink()->write(oggPage.header, oggPage.header_len);
written += getSink()->write( oggPage.body, oggPage.body_len);
if ( written < oggPage.header_len + oggPage.body_len ) {
reconnectError = true;
// just let go data that could not be written
reportEvent( 2,
"couldn't write full opus data to underlying sink",
oggPage.header_len + oggPage.body_len - written);
}
}
} else {
throw Exception( __FILE__, __LINE__, "internal ogg error");
}
}
/*------------------------------------------------------------------------------
* Close the encoding session
*----------------------------------------------------------------------------*/
void
OpusLibEncoder :: close ( void ) throw ( Exception )
{
if ( isOpen() ) {
flush();
ogg_stream_clear( &oggStreamState);
opus_encoder_destroy( opusEncoder);
opusEncoder = NULL;
encoderOpen = false;
if (internalBuffer) {
delete[] internalBuffer;
internalBuffer = NULL;
}
else {
fprintf(stderr, "Opus internalBuffer is NULL!\n");
}
getSink()->close();
}
}
#endif // HAVE_OPUS_LIB

View File

@ -0,0 +1,566 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : OpusLibEncoder.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef OPUS_LIB_ENCODER_H
#define OPUS_LIB_ENCODER_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#ifdef HAVE_OPUS_LIB
#include <opus/opus.h>
#include <ogg/ogg.h>
#else
#error configure for Ogg Opus
#endif
#include "Ref.h"
#include "Exception.h"
#include "Reporter.h"
#include "AudioEncoder.h"
#include "Sink.h"
#ifdef HAVE_SRC_LIB
#include <samplerate.h>
#else
#include "aflibConverter.h"
#endif
#include <stdio.h>
#include <cstdlib>
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A struct for containing the ogg opus header format, sent at the stream
* beginning.
*
* @author $Author$
* @version $Revision$
*/
struct OpusIdHeader {
char magic[8]; /* "OpusHead" */
unsigned char version; /* Version (currently 1) */
unsigned char channels; /* Number of channels */
unsigned short preskip; /* Pre-skip */
unsigned int samplerate; /* Original samplerate; informational only */
unsigned short gain; /* Output gain, stored in Q7.8 in dB */
unsigned char chanmap; /* 0 = mono or stereo L/R, 1=vorbis spec order, 2..254=reserved, 255=undef */
/**
* Build an Ogg packet from the header.
* @param packet output pointer, must be freed by caller
*
* @return number of bytes in packet.
*/
inline int buildPacket( unsigned char** packet) throw ( Exception ) {
int i = 0;
// FIXME - doesn't support multistream
unsigned char* out = (unsigned char*)malloc(19);
if( out == NULL ) {
throw Exception( __FILE__, __LINE__, "cannot alloc buffer");
}
for( ; i < 8; i++) {
out[i] = magic[i];
}
out[i++] = version;
out[i++] = channels;
out[i++] = preskip & 0xff;
out[i++] = (preskip >> 8) & 0xff;
out[i++] = samplerate & 0xff;
out[i++] = (samplerate >> 8) & 0xff;
out[i++] = (samplerate >> 16) & 0xff;
out[i++] = (samplerate >> 24) & 0xff;
out[i++] = gain & 0xff;
out[i++] = (gain >> 8) & 0xff;
out[i++] = chanmap;
*packet = out;
return i;
}
};
/**
* A struct for containing the ogg opus comment header format
*
* @author $Author$
* @version $Revision$
*/
struct OpusCommentHeader {
/**
* Struct for each tag pair, in the form of a UTF-8
* string, "TAG=value"
*
* @author $Author$
* @version $Revision$
*/
struct Tags {
unsigned int tag_len; /* For each tag, how long the following tag is */
char* tag_str; /* For each tag, UTF-8 encoded string, in tag=value */
};
char magic[8]; /* "OpusTags" */
unsigned int vendor_length; /* Length of the vendor string */
char* vendor_string; /* Vendor string -- parsed as utf-8 */
unsigned int num_tags; /* Number of tags following */
Tags* tags; /* Pointer to allocated tag array */
/**
* Build an Ogg packet from the header.
* @param packet output pointer, must be freed by caller
*
* @return number of bytes in packet.
*/
inline int buildPacket( unsigned char** packet) throw ( Exception ) {
int len = 8 + sizeof(unsigned int) * 2 + vendor_length;
int pos = 0;
for( unsigned int i = 0; i < num_tags; i++ )
{
len += sizeof(unsigned int) + tags[i].tag_len;
}
unsigned char* out = (unsigned char*)malloc(len);
if( out == NULL ) {
throw Exception( __FILE__, __LINE__, "cannot alloc buffer");
}
for( ; pos < 8; pos++) {
out[pos] = magic[pos];
}
out[pos++] = vendor_length & 0xff;
out[pos++] = (vendor_length >> 8) & 0xff;
out[pos++] = (vendor_length >> 16) & 0xff;
out[pos++] = (vendor_length >> 24) & 0xff;
for( unsigned int i = 0; i < vendor_length; i++ ) {
out[pos++] = vendor_string[i];
}
out[pos++] = num_tags & 0xff;
out[pos++] = (num_tags >> 8) & 0xff;
out[pos++] = (num_tags >> 16) & 0xff;
out[pos++] = (num_tags >> 24) & 0xff;
for( unsigned int i = 0; i < num_tags; i++ ) {
out[pos++] = tags[i].tag_len & 0xff;
out[pos++] = (tags[i].tag_len >> 8) & 0xff;
out[pos++] = (tags[i].tag_len >> 16) & 0xff;
out[pos++] = (tags[i].tag_len >> 24) & 0xff;
for( unsigned int j = 0; j < tags[i].tag_len; j++ ) {
out[pos++] = tags[i].tag_str[j];
}
}
*packet = out;
return len;
}
};
/**
* A class representing the ogg opus encoder linked as a shared object or
* as a static library.
*
* @author $Author$
* @version $Revision$
*/
class OpusLibEncoder : public AudioEncoder, public virtual Reporter
{
private:
/**
* Value indicating if the encoding process is going on
*/
bool encoderOpen;
/**
* Ogg Opus library global info
*/
OpusEncoder* opusEncoder;
/**
* Ogg library global stream state
*/
ogg_stream_state oggStreamState;
ogg_int64_t oggGranulePosition;
ogg_int64_t oggPacketNumber;
unsigned char* internalBuffer;
int internalBufferLength;
bool reconnectError;
/**
* Maximum bitrate of the output in kbits/sec. If 0, don't care.
*/
unsigned int outMaxBitrate;
/**
* Resample ratio
*/
double resampleRatio;
/**
* sample rate converter object for possible resampling
*/
#ifdef HAVE_SRC_LIB
SRC_STATE * converter;
SRC_DATA converterData;
#else
aflibConverter * converter;
#endif
/**
* Initialize the object.
*
* @param the maximum bit rate
* @exception Exception
*/
void
init ( unsigned int outMaxBitrate ) throw ( Exception );
/**
* De-initialize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
if ( converter ) {
#ifdef HAVE_SRC_LIB
delete [] converterData.data_in;
delete [] converterData.data_out;
src_delete (converter);
#else
delete converter;
#endif
}
}
/**
* Send pending Opus blocks to the underlying stream
*/
void
opusBlocksOut( int bytes,
unsigned char* data,
bool eos = false ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
OpusLibEncoder ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor.
*
* @param sink the sink to send encoded output to
* @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input.
* @param inBigEndian shows if the input is big or little endian
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, inSampleRate is used.
* @param outMaxBitrate maximum output bitrate.
* 0 if not used.
* @param outChannel number of channels of the output.
* If 0, inChannel is used.
* @exception Exception
*/
inline
OpusLibEncoder ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample,
unsigned int inChannel,
bool inBigEndian,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
unsigned int outMaxBitrate = 0 )
throw ( Exception )
: AudioEncoder ( sink,
inSampleRate,
inBitsPerSample,
inChannel,
inBigEndian,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( outMaxBitrate);
}
/**
* Constructor.
*
* @param sink the sink to send encoded output to
* @param as get input sample rate, bits per sample and channels
* from this AudioSource.
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, input sample rate is used.
* @param outMaxBitrate maximum output bitrate.
* 0 if not used.
* @param outChannel number of channels of the output.
* If 0, input channel is used.
* @exception Exception
*/
inline
OpusLibEncoder ( Sink * sink,
const AudioSource * as,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
unsigned int outMaxBitrate = 0 )
throw ( Exception )
: AudioEncoder ( sink,
as,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( outMaxBitrate);
}
/**
* Copy constructor.
*
* @param encoder the OpusLibEncoder to copy.
*/
inline
OpusLibEncoder ( const OpusLibEncoder & encoder )
throw ( Exception )
: AudioEncoder( encoder )
{
if( encoder.isOpen() ) {
throw Exception(__FILE__, __LINE__, "don't copy open encoders");
}
init( encoder.getOutMaxBitrate() );
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~OpusLibEncoder ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
strip();
}
/**
* Assignment operator.
*
* @param encoder the OpusLibEncoder to assign this to.
* @return a reference to this OpusLibEncoder.
* @exception Exception
*/
inline virtual OpusLibEncoder &
operator= ( const OpusLibEncoder & encoder ) throw ( Exception )
{
if( encoder.isOpen() ) {
throw Exception(__FILE__, __LINE__, "don't copy open encoders");
}
if ( this != &encoder ) {
strip();
AudioEncoder::operator=( encoder);
init( encoder.getOutMaxBitrate() );
}
return *this;
}
/**
* Get the maximum bit rate of the output in kbits/sec,
* for fixed / average bitrate encodings.
*
* @return the maximum bit rate of the output, or 0 if not set.
*/
inline unsigned int
getOutMaxBitrate ( void ) const throw ()
{
return outMaxBitrate;
}
/**
* Check whether encoding is in progress.
*
* @return true if encoding is in progress, false otherwise.
*/
inline virtual bool
isRunning ( void ) const throw ()
{
return isOpen();
}
/**
* Start encoding. This function returns as soon as possible,
* with encoding started in the background.
*
* @return true if encoding has started, false otherwise.
* @exception Exception
*/
inline virtual bool
start ( void ) throw ( Exception )
{
return open();
}
/**
* Stop encoding. Stops the encoding running in the background.
*
* @exception Exception
*/
inline virtual void
stop ( void ) throw ( Exception )
{
return close();
}
/**
* Open an encoding session.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the encoding session is open.
*
* @return true if the encoding session is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return encoderOpen;
}
/**
* Check if the encoder is ready to accept data.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the encoder is ready to accept data,
* false otherwise.
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
if ( !isOpen() ) {
return false;
}
return getSink()->canWrite(sec, usec);
}
/**
* Write data to the encoder.
* Buf is expected to be a sequence of big-endian 16 bit values,
* with left and right channels interleaved. Len is the number of
* bytes, must be a multiple of 4.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* Flush all data that was written to the encoder to the underlying
* connection.
*
* @exception Exception
*/
virtual void
flush ( void ) throw ( Exception );
/**
* Close the encoding session.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* OPUS_LIB_ENCODER_H */

View File

@ -0,0 +1,315 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : OssDspSource.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "OssDspSource.h"
#ifdef SUPPORT_OSS_DSP
// only compile this code if there is support for it
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#else
#error need sys/stat.h
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#error need fcntl.h
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#error need sys/time.h
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#else
#error need sys/ioctl.h
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#ifdef HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
#else
#error need sys/soundcard.h
#endif
#include "Util.h"
#include "Exception.h"
#include "OssDspSource.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/*------------------------------------------------------------------------------
* Define the natural endiannes of 16 bit recording if not defined,
* based on the endiannes of the system
*----------------------------------------------------------------------------*/
#ifndef AFMT_S16_NE
# ifdef WORDS_BIGENDIAN
# define AFMT_S16_NE AFMT_S16_BE
# else
# define AFMT_S16_NE AFMT_S16_LE
# endif
#endif
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Tell if source id big endian
*----------------------------------------------------------------------------*/
bool
OssDspSource :: isBigEndian ( void ) const throw ()
{
return AFMT_S16_NE == AFMT_S16_BE;
}
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
OssDspSource :: init ( const char * name ) throw ( Exception )
{
fileName = Util::strDup( name);
fileDescriptor = 0;
running = false;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
OssDspSource :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
delete[] fileName;
}
/*------------------------------------------------------------------------------
* Open the audio source
*----------------------------------------------------------------------------*/
bool
OssDspSource :: open ( void ) throw ( Exception )
{
int format;
int i;
unsigned int u;
if ( isOpen() ) {
return false;
}
switch ( getBitsPerSample() ) {
case 8:
format = AFMT_U8;
break;
case 16:
format = AFMT_S16_NE;
break;
default:
return false;
}
if ( (fileDescriptor = ::open( fileName, O_RDONLY)) == -1 ) {
fileDescriptor = 0;
return false;
}
i = format;
if ( ioctl( fileDescriptor, SNDCTL_DSP_SETFMT, &i) == -1 ||
i != format ) {
close();
throw Exception( __FILE__, __LINE__, "can't set format", i);
}
u = getChannel();
if ( ioctl( fileDescriptor, SNDCTL_DSP_CHANNELS, &u) == -1 ||
u != getChannel() ) {
close();
throw Exception( __FILE__, __LINE__, "can't set channels", u);
}
u = getSampleRate();
if ( ioctl( fileDescriptor, SNDCTL_DSP_SPEED, &u) == -1 ) {
close();
throw Exception( __FILE__, __LINE__,
"can't set soundcard recording sample rate", u);
}
if ( u != getSampleRate() ) {
reportEvent( 2, "sound card recording sample rate set to ", u,
" while trying to set it to ", getSampleRate());
reportEvent( 2, "this is probably not a problem, but a slight "
"drift in the sound card driver");
}
return true;
}
/*------------------------------------------------------------------------------
* Check whether read() would return anything
*----------------------------------------------------------------------------*/
bool
OssDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
fd_set fdset;
struct timespec timespec;
sigset_t sigset;
int ret;
if ( !isOpen() ) {
return false;
}
if ( !running ) {
/* ugly workaround to get the dsp into recording state */
unsigned char * b =
new unsigned char[getChannel()*getBitsPerSample()/8];
read( b, getChannel()*getBitsPerSample()/8);
delete[] b;
}
FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset);
timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( fileDescriptor + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error");
}
return ret > 0;
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
OssDspSource :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
ssize_t ret;
if ( !isOpen() ) {
return 0;
}
ret = ::read( fileDescriptor, buf, len);
if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "read error");
}
running = true;
return ret;
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
OssDspSource :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
::close( fileDescriptor);
fileDescriptor = 0;
running = false;
}
#endif // SUPPORT_OSS_DSP

View File

@ -0,0 +1,255 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : OssDspSource.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef OSS_DSP_SOURCE_H
#define OSS_DSP_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Reporter.h"
#include "AudioSource.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on /dev/dsp-like raw devices
*
* @author $Author$
* @version $Revision$
*/
class OssDspSource : public AudioSource, public virtual Reporter
{
private:
/**
* The file name of the OSS DSP device (e.g. /dev/dsp or /dev/dsp0).
*/
char * fileName;
/**
* The low-level file descriptor of the OSS DSP device.
*/
int fileDescriptor;
/**
* Indicates whether the low-level OSS DSP device is in a recording
* state.
*/
bool running;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
OssDspSource ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @param name the file name of the OSS DSP device.
* @exception Exception
*/
void
init ( const char * name ) throw ( Exception );
/**
* De-iitialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param name the file name of the OSS DSP device
* (e.g. /dev/dsp or /dev/dsp0).
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channel number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
OssDspSource ( const char * name,
int sampleRate = 44100,
int bitsPerSample = 16,
int channel = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channel)
{
init( name);
}
/**
* Copy Constructor.
*
* @param ods the object to copy.
* @exception Exception
*/
inline
OssDspSource ( const OssDspSource & ods ) throw ( Exception )
: AudioSource( ods )
{
init( ods.fileName);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~OssDspSource ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual OssDspSource &
operator= ( const OssDspSource & ds ) throw ( Exception )
{
if ( this != &ds ) {
strip();
AudioSource::operator=( ds);
init( ds.fileName);
}
return *this;
}
/**
* Tell if the data from this source comes in big or little endian.
*
* @return true if the source is big endian, false otherwise
*/
virtual bool
isBigEndian ( void ) const throw ();
/**
* Open the OssDspSource.
* This does not put the OSS DSP device into recording mode.
* To start getting samples, call either canRead() or read().
*
* @return true if opening was successful, false otherwise
* @exception Exception
*
* @see #canRead
* @see #read
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the OssDspSource is open.
*
* @return true if the OssDspSource is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return fileDescriptor != 0;
}
/**
* Check if the OssDspSource can be read from.
* Blocks until the specified time for data to be available.
* Puts the OSS DSP device into recording mode.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the OssDspSource is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the OssDspSource.
* Puts the OSS DSP device into recording mode.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the OssDspSource.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* OSS_DSP_SOURCE_H */

View File

@ -0,0 +1,237 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Copyright (c) 2004
LS Informationstechnik (LIKE)
University of Erlangen Nuremberg
All rights reserved.
Tyrell DarkIce
File : PulseAudioDspSource.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "AudioSource.h"
#include <stdio.h>
// compile only if configured for PULSEAUDIO
#ifdef SUPPORT_PULSEAUDIO_DSP
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "Util.h"
#include "Exception.h"
#include "PulseAudioDspSource.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
PulseAudioDspSource :: init ( const char * paSourceName ) throw ( Exception )
{
if (paSourceName == NULL)
{
throw Exception( __FILE__, __LINE__, "no paSourceName specified");
}
Reporter::reportEvent( 1, "Using PulseAudio source: ", paSourceName);
Util::strEq( paSourceName , "default" );
if (Util::strEq( paSourceName , "default" ))
{
sourceName = NULL;
}
else
{
sourceName = Util::strDup( paSourceName);
}
ss.channels = getChannel();
ss.rate = getSampleRate();
running = 0;
//Supported for some bits per sample, both Big and Little endian
if (isBigEndian())
{
switch (getBitsPerSample())
{
case 8:
ss.format = PA_SAMPLE_U8;
break;
case 16:
ss.format = PA_SAMPLE_S16BE;
break;
case 24:
ss.format = PA_SAMPLE_S24BE;
break;
case 32:
ss.format = PA_SAMPLE_S32BE;
break;
default:
ss.format = PA_SAMPLE_INVALID;
}
}
else
{
switch (getBitsPerSample())
{
case 8:
ss.format = PA_SAMPLE_U8;
break;
case 16:
ss.format = PA_SAMPLE_S16LE;
break;
case 24:
ss.format = PA_SAMPLE_S24LE;
break;
case 32:
ss.format = PA_SAMPLE_S32LE;
break;
default:
ss.format = PA_SAMPLE_INVALID;
}
}
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
PulseAudioDspSource :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
delete[] sourceName;
}
/*------------------------------------------------------------------------------
* Open the audio source
*----------------------------------------------------------------------------*/
bool
PulseAudioDspSource :: open ( void ) throw ( Exception )
{
char client_name[255];
//to identify each darkice on pulseaudio server
snprintf(client_name, 255, "darkice-%d", getpid());
if (!(s = pa_simple_new(NULL, client_name, PA_STREAM_RECORD, sourceName, "darkice record", &ss, NULL, NULL, &error))) {
throw Exception( __FILE__, __LINE__, ": pa_simple_new() failed: %s\n", pa_strerror(error));
}
running = 1;
return true;
}
/*------------------------------------------------------------------------------
* Check whether read() would return anything
*----------------------------------------------------------------------------*/
bool
PulseAudioDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
/** Strange have to remove this, need to investigate... */
/* if ( !isOpen() ) {
return false;
}
*/
if (running == 0) {
char client_name[255];
//to identify each darkice on pulseaudio server
snprintf(client_name, 255, "darkice-%d", getpid());
if (!(s = pa_simple_new(NULL, client_name, PA_STREAM_RECORD, sourceName, "darkice record", &ss, NULL, NULL, &error))) {
throw Exception( __FILE__, __LINE__, ": pa_simple_new() failed: %s\n", pa_strerror(error));
}
running = 1;
}
return true;
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
PulseAudioDspSource :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
int ret;
ret = pa_simple_read(s, buf, len, &error);
if ( ret < 0) {
throw Exception(__FILE__, __LINE__, ": pa_simple_read() failed: %s\n", pa_strerror(error));
}
return len;
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
PulseAudioDspSource :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
pa_simple_free(s);
running = 0;
}
#endif // HAVE_PULSEAUDIO_LIB

View File

@ -0,0 +1,495 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Copyright (c) 2004
LS Informationstechnik (LIKE)
University of Erlangen Nuremberg
All rights reserved.
Tyrell DarkIce
File : PulseAudioDspSource.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef PULSEAUDIO_SOURCE_H
#define PULSEAUDIO_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "Reporter.h"
#include "AudioSource.h"
#ifdef HAVE_PULSEAUDIO_LIB
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/gccmacro.h>
#else
#error configure for PULSEAUDIO
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on the PULSEAUDIO sound system
*
* @author $Author$
* @version $Revision$
*/
class PulseAudioDspSource : public AudioSource, public virtual Reporter
{
private:
/**
* Name of the capture PCM stream.
*/
char *sourceName;
/**
* Handle for PulseAudio
*/
pa_simple *s ;
/**
* format definitions for pulseaudio
*/
pa_sample_spec ss;
int running;
int error;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
PulseAudioDspSource ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @param name the PCM to open.
* @exception Exception
*/
void
init ( const char * name ) throw ( Exception );
/**
* De-iitialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param name the PCM (e.g. "hwplug:0,0").
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channel number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
PulseAudioDspSource ( const char * paSourceName,
int sampleRate = 44100,
int bitsPerSample = 16,
int channel = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channel)
{
init( paSourceName);
}
/**
* Copy Constructor.
*
* @param ds the object to copy.
* @exception Exception
*/
inline
PulseAudioDspSource ( const PulseAudioDspSource & ds ) throw ( Exception )
: AudioSource( ds )
{
init( ds.sourceName);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~PulseAudioDspSource ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual PulseAudioDspSource &
operator= ( const PulseAudioDspSource & ds ) throw ( Exception )
{
if ( this != &ds ) {
strip();
AudioSource::operator=( ds);
init( ds.sourceName);
}
return *this;
}
/**
* Open the PulseAudioDspSource.
*
* @return true if opening was successful, false otherwise
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the PulseAudioDspSource is open.
*
* @return true if the PulseAudioDspSource is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return s==NULL;
}
/**
* Check if the PulseAudioDspSource can be read from.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the PulseAudioDspSource is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the PulseAudioDspSource.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the PulseAudioDspSource.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* PULSEAUDIO_SOURCE_H */
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Copyright (c) 2004
LS Informationstechnik (LIKE)
University of Erlangen Nuremberg
All rights reserved.
Tyrell DarkIce
File : PulseAudioDspSource.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef PULSEAUDIO_SOURCE_H
#define PULSEAUDIO_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "Reporter.h"
#include "AudioSource.h"
#ifdef HAVE_PULSEAUDIO_LIB
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/gccmacro.h>
#else
#error configure for PULSEAUDIO
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on the PULSEAUDIO sound system
*
* @author $Author$
* @version $Revision$
*/
class PulseAudioDspSource : public AudioSource, public virtual Reporter
{
private:
/**
* Name of the capture PCM stream.
*/
char *sourceName;
/**
* Handle for PulseAudio
*/
pa_simple *s ;
/**
* format definitions for pulseaudio
*/
pa_sample_spec ss;
int error;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
PulseAudioDspSource ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @param name the PCM to open.
* @exception Exception
*/
void
init ( const char * name ) throw ( Exception );
/**
* De-iitialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param name the PCM (e.g. "hwplug:0,0").
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channel number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
PulseAudioDspSource ( const char * paSourceName,
int sampleRate = 44100,
int bitsPerSample = 16,
int channel = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channel)
{
init( paSourceName);
}
/**
* Copy Constructor.
*
* @param ds the object to copy.
* @exception Exception
*/
inline
PulseAudioDspSource ( const PulseAudioDspSource & ds ) throw ( Exception )
: AudioSource( ds )
{
init( ds.sourceName);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~PulseAudioDspSource ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual PulseAudioDspSource &
operator= ( const PulseAudioDspSource & ds ) throw ( Exception )
{
if ( this != &ds ) {
strip();
AudioSource::operator=( ds);
init( ds.sourceName);
}
return *this;
}
/**
* Open the PulseAudioDspSource.
*
* @return true if opening was successful, false otherwise
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the PulseAudioDspSource is open.
*
* @return true if the PulseAudioDspSource is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return s==NULL;
}
/**
* Check if the PulseAudioDspSource can be read from.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the PulseAudioDspSource is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the PulseAudioDspSource.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the PulseAudioDspSource.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* PULSEAUDIO_SOURCE_H */

View File

@ -0,0 +1,296 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Ref.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef REF_H
#define REF_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Exception.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Java-like object reference class.
* Objects used with this reference class have to be descandents
* of class Referable.
*
* sample usage:
*
* <pre>
* #include "Ref.h"
* #include "Referable.h"
*
* class A : public virtual Referable;
*
* ...
*
* A * a = new A();
* Ref<A> ref1 = a; // 1 reference to a
* Ref<A> ref2 = ref1; // 2 references to a
*
* ref1 = 0; // 1 reference to a
* ref2 = 0; // at this point object a is destroyed
* </pre>
*
* Based on Tima Saarinen's work,
* http://gamma.nic.fi/~timosa/comp/refcount.html
*
* @ref Referable
*
* @author $Author$
* @version $Revision$
*/
template <class T>
class Ref
{
private:
/**
* The object referenced by this Ref.
* Must be a descandant of Referable.
*/
T* object;
protected:
public:
/**
* Default constructor.
*/
inline
Ref ( void ) throw ()
{
object = NULL;
}
/**
* Copy constructor.
*
* @param other the Ref to copy.
* @exception Exception
*/
inline
Ref ( const Ref<T> & other ) throw ( Exception )
{
object = NULL;
set( other.object);
}
/**
* Constructor based on an object to reference.
*
* @param obj the object to reference.
* @exception Exception
*/
inline
Ref ( T * obj ) throw ( Exception )
{
object = obj;
obj->increaseReferenceCount();
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~Ref ( void ) throw ( Exception )
{
set( 0 );
}
/**
* Operator overload to make the reference seem like a pointer.
*
* @return the pointer to the object referenced.
*/
inline T*
operator->() const throw ( Exception )
{
if ( !object ) {
throw Exception( __FILE__, __LINE__,
"reference to NULL object");
}
return object;
}
/**
* Assignment operator.
*
* @param other the Ref to assign to this one.
* @return a reference to this Ref.
* @exception Exception
*/
inline Ref<T> &
operator= ( Ref<T> other ) throw ( Exception )
{
set( other.object);
return *this;
}
/**
* Assignment operator.
*
* @param obj pointer to the object to assign to this Ref.
* @return a reference to this Ref.
* @exception Exception
*/
inline Ref<T> &
operator= ( T* obj ) throw ( Exception )
{
set( obj);
return *this;
}
/**
* Set the object referenced.
* Deletes the old referenced object is this was it's last reference.
*
* @param newobj pointer to the object to reference by this Ref.
* @exception Exception
*/
inline void
set ( T * newobj ) throw ( Exception )
{
// If equal do nothing
if ( newobj == object ) {
return;
}
// Increase reference count
if ( newobj ) {
newobj->increaseReferenceCount();
}
// Decrease the reference count of the old referable
if ( object ) {
if ( object->decreaseReferenceCount() == 0 ) {
delete object;
}
}
// Assign
object = newobj;
}
/**
* Return object pointer. This method should be used with
* care because it breaks the encapsulation.
* Typically this method is needed for the method calls
* which require literal object pointer.
*
* It may not be bad idea to pass the Ref
* objects as method arguments.
*
* @return Object pointer or NULL.
*/
inline T*
get ( void ) const throw ()
{
return object;
}
/**
* Equality operator.
*
* @param other the pointer to compare this with.
* @return true is this Ref refers to the same object as other,
* false otherwise.
*/
inline bool
operator== ( const T * other ) const throw ()
{
return object == other;
}
/**
* Equality operator.
*
* @param other the Ref to compare this with.
* @return true is the two Refs refer to the same object,
* false otherwise.
*/
inline bool
operator== ( const Ref<T> & other ) const throw ()
{
return object == other.object;
}
/**
* Unequality operator.
*
* @param other the pointer to compare this with.
* @return false is this Ref refers to a different object then other,
* true otherwise.
*/
inline bool
operator!= ( const T * other ) const throw ()
{
return object != other;
}
/**
* Unequality operator.
*
* @param other the Ref to compare this with.
* @return false is the two Refs refer to the same object,
* true otherwise.
*/
inline bool
operator!= ( const Ref<T> & other ) const throw ()
{
return object != other.object;
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* REF_H */

View File

@ -0,0 +1,170 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Referable.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef REFERABLE_H
#define REFERABLE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Exception.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Base class for an object for which references can be made
* with the reference class Ref.
*
* usage:
*
* <pre>
* class A : public virtual Referable
* {
* ...
* };
* </pre>
*
* @ref Ref
*
* @author $Author$
* @version $Revision$
*/
class Referable
{
private:
/**
* Number of references to the object.
*/
unsigned int referenceCount;
/**
* Maximum number of references before an overflow occurs.
*/
static const
unsigned int maxCount = ~((unsigned int)0);
protected:
/**
* Default constructor.
*/
inline
Referable ( void ) throw ()
{
referenceCount = 0;
}
/**
* Desctructor.
*
* @exception Exception
*/
inline virtual
~Referable ( void ) throw ( Exception )
{
if ( referenceCount > 0 ) {
throw Exception( __FILE__, __LINE__,
"reference count positive in destructor",
referenceCount);
}
}
public:
/**
* Increase reference count.
*
* @return the new reference count.
* @exception Exception
*/
inline unsigned int
increaseReferenceCount ( void ) throw ( Exception )
{
if ( referenceCount >= maxCount ) {
throw Exception( __FILE__,
__LINE__,
"reference count overflow",
referenceCount );
}
return ++referenceCount;
}
/**
* Decrease reference count.
*
* @return the new reference count.
* @exception Exception
*/
inline unsigned int
decreaseReferenceCount ( void ) throw ( Exception )
{
if ( referenceCount == 0 ) {
throw Exception( __FILE__, __LINE__,
"reference count underflow",
referenceCount );
}
return --referenceCount;
}
/**
* Get the reference count.
*
* @return the reference count.
*/
inline unsigned int
getReferenceCount ( void ) const throw ()
{
return referenceCount;
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* REFERABLE_H */

View File

@ -0,0 +1,60 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell Reporter
File : Reporter.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include <iostream>
#include "Reporter.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/*------------------------------------------------------------------------------
* Initial values for static members of the class
*----------------------------------------------------------------------------*/
unsigned int Reporter::verbosity = 1;
std::ostream * Reporter::os = &std::cout;
/* =============================================== local function prototypes */
/* ============================================================= module code */

View File

@ -0,0 +1,305 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell Reporter
File : Reporter.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef REPORTER_H
#define REPORTER_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#else
#error need time.h
#endif
#include <iostream>
#include "Exception.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Class for reporting events. All objects of this class share
* the same verbosity level. Typical usage is to inherit this class
* and use the report() function to report events. Only reports
* which are of suffucient importance are really reported.
*
* The default verbosity is 1, and the default ostream is cout.
*
* Known problems: this class is not thread-safe.
*
* @author $Author$
* @version $Revision$
*/
class Reporter
{
private:
/**
* Verbosity level shared among all Reporter objects
*/
static unsigned int verbosity;
/**
* The output stream to report to.
*/
static std::ostream * os;
/**
* Print timestamp for every report only if verbosity level
* is above this value.
*/
static const unsigned int prefixVerbosity = 3;
/**
* Print a prefix to each report.
*/
static void
printPrefix( void ) throw ()
{
if ( verbosity > prefixVerbosity ) {
char str[32];
time_t now;
now = time(NULL);
strftime( str, 32, "%d-%b-%Y %H:%M:%S ", localtime(&now) );
(*(Reporter::os)) << str;
}
}
protected:
public:
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~Reporter ( void ) throw ( Exception )
{
(Reporter::os)->flush();
}
/**
* Set the verbosity level. This sets the verbosity for all
* Reporter objects.
*
* @param verbosity the new verbosity level.
*/
static inline void
setReportVerbosity ( unsigned int verbosity ) throw ()
{
Reporter::verbosity = verbosity;
}
/**
* Get the verbosity level.
*
* @return the current verbosity level.
*/
static inline unsigned int
getReportVerbosity ( void ) throw ()
{
return Reporter::verbosity;
}
/**
* Set the output stream to report to. This setting effects all
* Reporter objects.
*
* @param os the output stream
*/
static inline void
setReportOutputStream ( std::ostream & os ) throw ()
{
Reporter::os = &os;
}
/**
* Get the output stream to report to.
*
* @return the output stream
*/
static inline std::ostream &
getReportOutputStream ( void ) throw ()
{
return *(Reporter::os);
}
/**
* Report an event with a given verbosity.
*
* @param verbosity the importance of the event, with 0 being
* the most important.
* @param t the object to report. Must have an
* <code>ostream & operator<<( ostream&, const T)</code>
* operator overload.
*/
template<class T>
static inline void
reportEvent ( unsigned int verbosity,
const T t ) throw ()
{
if ( Reporter::verbosity >= verbosity ) {
printPrefix();
(*(Reporter::os)) << t << std::endl;
}
}
/**
* Report an event with a given verbosity.
*
* @param verbosity the importance of the event, with 0 being
* the most important.
* @param t the object 1 to report. Must have an
* <code>ostream & operator<<( ostream&, const T)</code>
* operator overload.
* @param u the object 2 to report. Must have an
* <code>ostream & operator<<( ostream&, const U)</code>
* operator overload.
*/
template<class T, class U>
inline void
static reportEvent ( unsigned int verbosity,
const T t,
const U u ) throw ()
{
if ( Reporter::verbosity >= verbosity ) {
printPrefix();
(*(Reporter::os)) << t << " "
<< u << std::endl;
}
}
/**
* Report an event with a given verbosity.
*
* @param verbosity the importance of the event, with 0 being
* the most important.
* @param t the object 1 to report. Must have an
* <code>ostream & operator<<( ostream&, const T)</code>
* operator overload.
* @param u the object 2 to report. Must have an
* <code>ostream & operator<<( ostream&, const U)</code>
* operator overload.
* @param v the object 3 to report. Must have an
* <code>ostream & operator<<( ostream&, const V)</code>
* operator overload.
*/
template<class T, class U, class V>
static inline void
reportEvent ( unsigned int verbosity,
const T t,
const U u,
const V v ) throw ()
{
if ( Reporter::verbosity >= verbosity ) {
printPrefix();
(*(Reporter::os)) << t << " "
<< u << " "
<< v << std::endl;
}
}
/**
* Report an event with a given verbosity.
*
* @param verbosity the importance of the event, with 0 being
* the most important.
* @param t the object 1 to report. Must have an
* <code>ostream & operator<<( ostream&, const T)</code>
* operator overload.
* @param u the object 2 to report. Must have an
* <code>ostream & operator<<( ostream&, const U)</code>
* operator overload.
* @param v the object 3 to report. Must have an
* <code>ostream & operator<<( ostream&, const V)</code>
* operator overload.
* @param w the object 4 to report. Must have an
* <code>ostream & operator<<( ostream&, const W)</code>
* operator overload.
*/
template<class T, class U, class V, class W>
static inline void
reportEvent ( unsigned int verbosity,
const T t,
const U u,
const V v,
const W w ) throw ()
{
if ( Reporter::verbosity >= verbosity ) {
printPrefix();
(*(Reporter::os)) << t << " "
<< u << " "
<< v << " "
<< w << std::endl;
}
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* REPORTER_H */

View File

@ -0,0 +1,338 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000 Tyrell Corporation.
Copyright (c) 2006 Clyde Stubbs.
Tyrell DarkIce
File : SerialUlaw.cpp
Version : $Revision$
Author : $Author$
Location : $Source: /cvsroot/darkice/darkice/src/SerialUlaw.cpp,v $
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "SerialUlaw.h"
#ifdef SUPPORT_SERIAL_ULAW
// only compile this code if there's support for it
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#else
#error need stdio.h
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#else
#error need sys/stat.h
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#error need fcntl.h
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#error need sys/time.h
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#else
#error need sys/ioctl.h
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#else
#error need termios.h
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#include "Util.h"
#include "Exception.h"
#include "SerialUlaw.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/*------------------------------------------------------------------------------
* Ulaw decode table
*----------------------------------------------------------------------------*/
static unsigned int ulawdecode[256] =
{
0x8284,0x8684,0x8a84,0x8e84,0x9284,0x9684,0x9a84,0x9e84,
0xa284,0xa684,0xaa84,0xae84,0xb284,0xb684,0xba84,0xbe84,
0xc184,0xc384,0xc584,0xc784,0xc984,0xcb84,0xcd84,0xcf84,
0xd184,0xd384,0xd584,0xd784,0xd984,0xdb84,0xdd84,0xdf84,
0xe104,0xe204,0xe304,0xe404,0xe504,0xe604,0xe704,0xe804,
0xe904,0xea04,0xeb04,0xec04,0xed04,0xee04,0xef04,0xf004,
0xf0c4,0xf144,0xf1c4,0xf244,0xf2c4,0xf344,0xf3c4,0xf444,
0xf4c4,0xf544,0xf5c4,0xf644,0xf6c4,0xf744,0xf7c4,0xf844,
0xf8a4,0xf8e4,0xf924,0xf964,0xf9a4,0xf9e4,0xfa24,0xfa64,
0xfaa4,0xfae4,0xfb24,0xfb64,0xfba4,0xfbe4,0xfc24,0xfc64,
0xfc94,0xfcb4,0xfcd4,0xfcf4,0xfd14,0xfd34,0xfd54,0xfd74,
0xfd94,0xfdb4,0xfdd4,0xfdf4,0xfe14,0xfe34,0xfe54,0xfe74,
0xfe8c,0xfe9c,0xfeac,0xfebc,0xfecc,0xfedc,0xfeec,0xfefc,
0xff0c,0xff1c,0xff2c,0xff3c,0xff4c,0xff5c,0xff6c,0xff7c,
0xff88,0xff90,0xff98,0xffa0,0xffa8,0xffb0,0xffb8,0xffc0,
0xffc8,0xffd0,0xffd8,0xffe0,0xffe8,0xfff0,0xfff8,0x0000,
0x7d7c,0x797c,0x757c,0x717c,0x6d7c,0x697c,0x657c,0x617c,
0x5d7c,0x597c,0x557c,0x517c,0x4d7c,0x497c,0x457c,0x417c,
0x3e7c,0x3c7c,0x3a7c,0x387c,0x367c,0x347c,0x327c,0x307c,
0x2e7c,0x2c7c,0x2a7c,0x287c,0x267c,0x247c,0x227c,0x207c,
0x1efc,0x1dfc,0x1cfc,0x1bfc,0x1afc,0x19fc,0x18fc,0x17fc,
0x16fc,0x15fc,0x14fc,0x13fc,0x12fc,0x11fc,0x10fc,0x0ffc,
0x0f3c,0x0ebc,0x0e3c,0x0dbc,0x0d3c,0x0cbc,0x0c3c,0x0bbc,
0x0b3c,0x0abc,0x0a3c,0x09bc,0x093c,0x08bc,0x083c,0x07bc,
0x075c,0x071c,0x06dc,0x069c,0x065c,0x061c,0x05dc,0x059c,
0x055c,0x051c,0x04dc,0x049c,0x045c,0x041c,0x03dc,0x039c,
0x036c,0x034c,0x032c,0x030c,0x02ec,0x02cc,0x02ac,0x028c,
0x026c,0x024c,0x022c,0x020c,0x01ec,0x01cc,0x01ac,0x018c,
0x0174,0x0164,0x0154,0x0144,0x0134,0x0124,0x0114,0x0104,
0x00f4,0x00e4,0x00d4,0x00c4,0x00b4,0x00a4,0x0094,0x0084,
0x0078,0x0070,0x0068,0x0060,0x0058,0x0050,0x0048,0x0040,
0x0038,0x0030,0x0028,0x0020,0x0018,0x0010,0x0008,0x0000,
};
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Tell if source id big endian
*----------------------------------------------------------------------------*/
bool
SerialUlaw :: isBigEndian ( void ) const throw ()
{
return false;
}
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
SerialUlaw :: init ( const char * name ) throw ( Exception )
{
fileName = Util::strDup( name);
fileDescriptor = 0;
running = false;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
SerialUlaw :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
delete[] fileName;
}
/*------------------------------------------------------------------------------
* Open the audio source
*----------------------------------------------------------------------------*/
bool
SerialUlaw :: open ( void ) throw ( Exception )
{
struct termios ts;
if ( isOpen() ) {
return false;
}
switch ( getBitsPerSample() ) {
case 16:
break;
default:
return false;
}
if (getChannel() != 1) {
reportEvent(3, "Only mono input supported for Serial ULaw");
return false;
}
if (getSampleRate() != 8000) {
reportEvent(3, "Only 8000 Hz sample rate supported for Serial ULaw");
return false;
}
if ( (fileDescriptor = ::open( fileName, O_RDONLY)) == -1 ) {
fileDescriptor = 0;
return false;
}
if(tcgetattr(fileDescriptor, &ts) < 0) {
close();
throw Exception( __FILE__, __LINE__, "can't get tty settings");
}
cfsetispeed(&ts, B115200);
cfmakeraw(&ts);
ts.c_cflag |= CLOCAL;
if(tcsetattr(fileDescriptor, TCSANOW, &ts) < 0) {
close();
throw Exception( __FILE__, __LINE__, "can't set tty settings");
}
tcflush(fileDescriptor, TCIFLUSH);
return true;
}
/*------------------------------------------------------------------------------
* Check whether read() would return anything
*----------------------------------------------------------------------------*/
bool
SerialUlaw :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
fd_set fdset;
struct timeval tv;
int ret;
if ( !isOpen() ) {
return false;
}
FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset);
tv.tv_sec = sec;
tv.tv_usec = usec;
ret = select( fileDescriptor + 1, &fdset, NULL, NULL, &tv);
if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error");
}
return ret > 0;
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
SerialUlaw :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
ssize_t ret;
unsigned char ubuf[256], * ptr;
int i, plen;
if ( !isOpen() ) {
return 0;
}
ret = 0;
ptr = (unsigned char *)buf;
while(len > 1) {
plen = sizeof(ubuf);
if (plen > (int)len/2) {
plen = len/2;
}
plen = ::read( fileDescriptor, ubuf, plen);
if(plen < 0) {
perror("read");
throw Exception( __FILE__, __LINE__, "read error");
}
for(i = 0 ; i != plen ; i++) {
*ptr++ = ulawdecode[ubuf[i]] & 0xFF;
*ptr++ = ulawdecode[ubuf[i]] >> 8;
}
len -= plen*2;
ret += plen*2;
}
running = true;
return ret;
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
SerialUlaw :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
::close( fileDescriptor);
fileDescriptor = 0;
running = false;
}
#endif // SUPPORT_SERIAL_ULAW

View File

@ -0,0 +1,255 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Copyright (c) 2007 Clyde Stubbs
Tyrell DarkIce
File : SerialUlaw.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef SERIAL_ULAW_SOURCE_H
#define SERIAL_ULAW_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Reporter.h"
#include "AudioSource.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on /dev/dsp-like raw devices
*
* @author $Author$
* @version $Revision$
*/
class SerialUlaw : public AudioSource, public virtual Reporter
{
private:
/**
* The file name of the OSS DSP device (e.g. /dev/dsp or /dev/dsp0).
*/
char * fileName;
/**
* The low-level file descriptor of the OSS DSP device.
*/
int fileDescriptor;
/**
* Indicates whether the low-level OSS DSP device is in a recording
* state.
*/
bool running;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
SerialUlaw ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @param name the file name of the OSS DSP device.
* @exception Exception
*/
void
init ( const char * name ) throw ( Exception );
/**
* De-iitialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param name the file name of the OSS DSP device
* (e.g. /dev/dsp or /dev/dsp0).
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channel number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
SerialUlaw ( const char * name,
int sampleRate = 44100,
int bitsPerSample = 16,
int channel = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channel)
{
init( name);
}
/**
* Copy Constructor.
*
* @param ods the object to copy.
* @exception Exception
*/
inline
SerialUlaw ( const SerialUlaw & ods ) throw ( Exception )
: AudioSource( ods )
{
init( ods.fileName);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~SerialUlaw ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual SerialUlaw &
operator= ( const SerialUlaw & ds ) throw ( Exception )
{
if ( this != &ds ) {
strip();
AudioSource::operator=( ds);
init( ds.fileName);
}
return *this;
}
/**
* Tell if the data from this source comes in big or little endian.
*
* @return true if the source is big endian, false otherwise
*/
virtual bool
isBigEndian ( void ) const throw ();
/**
* Open the SerialUlaw.
* This does not put the OSS DSP device into recording mode.
* To start getting samples, call either canRead() or read().
*
* @return true if opening was successful, false otherwise
* @exception Exception
*
* @see #canRead
* @see #read
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the SerialUlaw is open.
*
* @return true if the SerialUlaw is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return fileDescriptor != 0;
}
/**
* Check if the SerialUlaw can be read from.
* Blocks until the specified time for data to be available.
* Puts the OSS DSP device into recording mode.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the SerialUlaw is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the SerialUlaw.
* Puts the OSS DSP device into recording mode.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the SerialUlaw.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* SERIAL_ULAW_SOURCE_H */

View File

@ -0,0 +1,253 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : ShoutCast.cpp
Version : $Revision$
Author : $Author$
Location : $Source$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#else
#error need stdio.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#else
#error need math.h
#endif
#include <sstream>
#include "Exception.h"
#include "Source.h"
#include "Sink.h"
#include "Util.h"
#include "ShoutCast.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/*------------------------------------------------------------------------------
* Size of string conversion buffer
*----------------------------------------------------------------------------*/
#define STRBUF_SIZE 32
#define HEADERLINE_LENGTH 50
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
ShoutCast :: init ( const char * irc,
const char * aim,
const char * icq,
const char * mountPoint )
throw ( Exception )
{
this->irc = irc ? Util::strDup( irc) : 0;
this->aim = aim ? Util::strDup( aim) : 0;
this->icq = icq ? Util::strDup( icq) : 0;
this->mountPoint = mountPoint ? Util::strDup( mountPoint ) : 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
ShoutCast :: strip ( void ) throw ( Exception )
{
if ( irc ) {
delete[] irc;
}
if ( aim ) {
delete[] aim;
}
if ( icq ) {
delete[] icq;
}
if (mountPoint ){
delete[] mountPoint;
}
}
/*------------------------------------------------------------------------------
* Log in to the ShoutCast server using the icy login scheme
*----------------------------------------------------------------------------*/
bool
ShoutCast :: sendLogin ( void ) throw ( Exception )
{
Sink * sink = getSink();
Source * source = getSocket();
const char * str;
char resp[STRBUF_SIZE];
unsigned int len;
bool needsMountPoint = false;
const char * mountPoint = getMountPoint();
char header_line[HEADERLINE_LENGTH+2]; // ... + \n + \0
if ( !source->isOpen() ) {
return false;
}
if ( !sink->isOpen() ) {
return false;
}
// We will add SOURCE only if really needed: if the mountPoint is not null
// and is different of "/". This is to keep maximum compatibility with
// NullSoft Shoutcast server.
if (mountPoint != 0L
&& strlen(mountPoint) > 0 && 0 != strcmp("/", mountPoint)) {
needsMountPoint = true;
}
std::ostringstream os;
if (needsMountPoint) {
os << "SOURCE ";
}
/* first line is the password in itself */
os << getPassword();
os << "\n";
// send the mount point
if (needsMountPoint) {
os << " ";
if (strncmp("/", mountPoint, 1) != 0) {
os << "/";
}
os << mountPoint;
os << "\n";
}
str = os.str().c_str();
// Ok, now we send login which will be different of classical Shoutcast
// if mountPoint is not null and is different from "/" ...
sink->write( str, strlen( str));
sink->flush();
/* read the anticipated response: "OK" */
len = source->read( resp, STRBUF_SIZE);
reportEvent(8, "server response length: ", len);
reportEvent(8, "server response: ", resp);
if ( Util::strEq( resp, "invalid password",16) ) {
throw Exception( __FILE__, __LINE__,
"ShoutCast - wrong password");
}
if ( len < 2 || resp[0] != 'O' || resp[1] != 'K' ) {
return false;
}
/* suck anything that the other side has to say */
while ( source->canRead( 0, 0) &&
(len = source->read( resp, STRBUF_SIZE)) ) {
;
}
/* send the icy headers */
if ( getName() ) {
snprintf(header_line, HEADERLINE_LENGTH, "icy-name:%s", getName());
strcat(header_line, "\n");
sink->write( header_line, strlen( header_line));
}
if ( getUrl() ) {
snprintf(header_line, HEADERLINE_LENGTH, "icy-url:%s", getUrl());
strcat(header_line, "\n");
sink->write( header_line, strlen( header_line));
}
if ( getGenre() ) {
snprintf(header_line, HEADERLINE_LENGTH, "icy-genre:%s", getGenre());
strcat(header_line, "\n");
sink->write( header_line, strlen( header_line));
}
if ( getIrc() ) {
snprintf(header_line, HEADERLINE_LENGTH, "icy-irc:%s", getIrc());
strcat(header_line, "\n");
sink->write( header_line, strlen( header_line));
}
if ( getAim() ) {
snprintf(header_line, HEADERLINE_LENGTH, "icy-aim:%s", getAim());
strcat(header_line, "\n");
sink->write( header_line, strlen( header_line));
}
if ( getIcq() ) {
snprintf(header_line, HEADERLINE_LENGTH, "icy-icq:%s", getIcq());
strcat(header_line, "\n");
sink->write( header_line, strlen( header_line));
}
snprintf(header_line, HEADERLINE_LENGTH, "icy-br:%d", getBitRate());
strcat(header_line, "\n");
sink->write( header_line, strlen( header_line));
snprintf(header_line, HEADERLINE_LENGTH, "icy-pub:%s", getIsPublic() ? "1" : "0");
strcat(header_line, "\n");
sink->write( header_line, strlen( header_line));
str = "\n";
sink->write( str, strlen( str));
sink->flush();
return true;
}

View File

@ -0,0 +1,279 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : ShoutCast.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef SHOUT_CAST_H
#define SHOUT_CAST_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Sink.h"
#include "TcpSocket.h"
#include "CastSink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Class representing output to a ShoutCast server with
* icy login
*
* @author $Author$
* @version $Revision$
*/
class ShoutCast : public CastSink
{
private:
/**
* IRC info string for the stream
*/
char * irc;
/**
* AIM info string for the stream
*/
char * aim;
/**
* ICQ info string for the stream
*/
char * icq;
/**
* The optional mountPoint
*/
char * mountPoint;
/**
* Initalize the object.
*
* @param irc IRC info string for the stream.
* @param aim AIM info string for the stream.
* @param icq ICQ info string for the stream.
* @param mountPoint Optional mount point information
* @exception Exception
*/
void
init ( const char * irc,
const char * aim,
const char * icq,
const char * mountPoint )
throw ( Exception );
/**
* De-initalize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
ShoutCast ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Log in to the server using the socket avialable.
*
* @return true if login was successful, false otherwise.
* @exception Exception
*/
virtual bool
sendLogin ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param socket socket connection to the server.
* @param password password to the server.
* @param mountPoint Optional mount point for DSS.
* @param name name of the stream.
* @param url URL associated with the stream.
* @param genre genre of the stream.
* @param bitRate bitrate of the stream (e.g. mp3 bitrate).
* @param isPublic is the stream public?
* @param irc IRC info string for the stream.
* @param aim AIM info string for the stream.
* @param icq ICQ info string for the stream.
* @param streamDump an optional sink to dump the binary stream
* data to.
* @param bufferDuration duration of the BufferedSink buffer
* in seconds.
* @exception Exception
*/
inline
ShoutCast ( TcpSocket * socket,
const char * password,
const char * mountPoint,
unsigned int bitRate,
const char * name = 0,
const char * url = 0,
const char * genre = 0,
bool isPublic = false,
const char * irc = 0,
const char * aim = 0,
const char * icq = 0,
Sink * streamDump = 0 )
throw ( Exception )
: CastSink( socket,
password,
bitRate,
name,
url,
genre,
isPublic,
streamDump )
{
init( irc, aim, icq, mountPoint );
}
/**
* Copy constructor.
*
* @param cs the ShoutCast to copy.
*/
inline
ShoutCast( const ShoutCast & cs ) throw ( Exception )
: CastSink( cs )
{
init( cs.getIrc(), cs.getAim(), cs.getIcq(), cs.getMountPoint());
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~ShoutCast( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param cs the ShoutCast to assign this to.
* @return a reference to this ShoutCast.
* @exception Exception
*/
inline virtual ShoutCast &
operator= ( const ShoutCast & cs ) throw ( Exception )
{
if ( this != &cs ) {
strip();
CastSink::operator=( cs );
init( cs.getIrc(), cs.getAim(), cs.getIcq(), getMountPoint());
}
return *this;
}
/**
* Get the mount point of the stream on the server.
* The mount point can be null if it has not been set
* (typical Shoutcast server) or not null (for instance
* with Darwin Streaming Server). In that case, the
* authentication process will be slightly different.
*
* @return the mount point of the stream on the server.
*/
inline const char *
getMountPoint ( void ) const throw ()
{
return mountPoint;
}
/**
* Get the IRC info string for the stream.
*
* @return the IRC info string for the stream.
*/
inline const char *
getIrc ( void ) const throw ()
{
return irc;
}
/**
* Get the AIM info string for the stream.
*
* @return the AIM info string for the stream.
*/
inline const char *
getAim ( void ) const throw ()
{
return aim;
}
/**
* Get the ICQ info string for the stream.
*
* @return the ICQ info string for the stream.
*/
inline const char *
getIcq ( void ) const throw ()
{
return icq;
}
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* SHOUT_CAST_H */

View File

@ -0,0 +1,185 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Sink.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef SINK_H
#define SINK_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Referable.h"
#include "Exception.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A general data sink
*
* @author $Author$
* @version $Revision$
*/
class Sink : public virtual Referable
{
private:
protected:
/**
* Default constructor.
*/
inline
Sink ( void ) throw ()
{
}
/**
* Copy constructor.
*
* @param sink the Sink to copy.
*/
inline
Sink ( const Sink & sink ) throw ()
{
}
/**
* Assignment operator.
*
* @param sink the Sink to assign this to.
* @return a reference to this Sink.
* @exception Exception
*/
inline virtual Sink &
operator= ( const Sink & sink ) throw ( Exception )
{
return *this;
}
public:
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~Sink ( void ) throw ( Exception )
{
}
/**
* Open the sink.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception ) = 0;
/**
* Check if the Sink is open.
*
* @return true if the Sink is open, false otherwise.
*/
virtual bool
isOpen ( void ) const throw () = 0;
/**
* Check if the Sink is ready to accept data.
* Blocks until the specified time for data to be available.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the Sink is ready to accept data, false otherwise.
* @exception Exception
*/
virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception ) = 0;
/**
* Write data to the Sink.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception ) = 0;
/**
* Flush all data that was written to the Sink to the underlying
* construct.
*
* @exception Exception
*/
virtual void
flush ( void ) throw ( Exception ) = 0;
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
virtual void
cut ( void ) throw () = 0;
/**
* Close the Sink.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception ) = 0;
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* SINK_H */

View File

@ -0,0 +1,277 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : SolarisDspSource.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "SolarisDspSource.h"
#ifdef SUPPORT_SOLARIS_DSP
// only compile this code if there is support for it
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#else
#error need sys/stat.h
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#error need fcntl.h
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#error need sys/time.h
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#else
#error need sys/ioctl.h
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#if defined( HAVE_SYS_AUDIO_H )
#include <sys/audio.h>
#elif defined( HAVE_SYS_AUDIOIO_H )
#include <sys/audioio.h>
#else
#error need sys/audio.h or sys/audioio.h
#endif
#include "Util.h"
#include "Exception.h"
#include "SolarisDspSource.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
SolarisDspSource :: init ( const char * name ) throw ( Exception )
{
fileName = Util::strDup( name);
fileDescriptor = 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
SolarisDspSource :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
delete[] fileName;
}
#include <errno.h>
/*------------------------------------------------------------------------------
* Open the audio source
*----------------------------------------------------------------------------*/
bool
SolarisDspSource :: open ( void ) throw ( Exception )
{
audio_info_t audioInfo;
if ( isOpen() ) {
return false;
}
if ( (fileDescriptor = ::open( fileName, O_RDONLY)) == -1 ) {
fileDescriptor = 0;
return false;
}
AUDIO_INITINFO( &audioInfo);
audioInfo.record.sample_rate = getSampleRate();
audioInfo.record.channels = getChannel();
audioInfo.record.precision = getBitsPerSample();
audioInfo.record.encoding = AUDIO_ENCODING_LINEAR;
// for stupid OpenBSD we need to add the following, as it masks
// read/write calls when using -pthread
audioInfo.record.pause = 0;
if ( ioctl( fileDescriptor, AUDIO_SETINFO, &audioInfo) == -1 ) {
close();
throw Exception( __FILE__, __LINE__, "ioctl error");
}
if ( audioInfo.record.channels != getChannel() ) {
close();
throw Exception( __FILE__, __LINE__,
"can't set channels", audioInfo.record.channels);
}
if ( audioInfo.record.precision != getBitsPerSample() ) {
close();
throw Exception( __FILE__, __LINE__,
"can't set bits per sample",
audioInfo.record.precision);
}
if ( audioInfo.record.sample_rate != getSampleRate() ) {
reportEvent( 2, "sound card recording sample rate set to ",
audioInfo.record.sample_rate,
" while trying to set it to ", getSampleRate());
reportEvent( 2, "this is probably not a problem, but a slight "
"drift in the sound card driver");
}
return true;
}
/*------------------------------------------------------------------------------
* Check whether read() would return anything
*----------------------------------------------------------------------------*/
bool
SolarisDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
fd_set fdset;
struct timespec timespec;
sigset_t sigset;
int ret;
if ( !isOpen() ) {
return false;
}
FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset);
timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( fileDescriptor + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error");
}
return ret > 0;
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
SolarisDspSource :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
ssize_t ret;
if ( !isOpen() ) {
return 0;
}
ret = ::read( fileDescriptor, buf, len);
if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "read error");
}
return ret;
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
SolarisDspSource :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
::close( fileDescriptor);
fileDescriptor = 0;
}
#endif // SUPPORT_SOLARIS_DSP

View File

@ -0,0 +1,257 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : SolarisDspSource.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef SOLARIS_DSP_SOURCE_H
#define SOLARIS_DSP_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Reporter.h"
#include "AudioSource.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on Solaris /dev/audio devices
*
* @author $Author$
* @version $Revision$
*/
class SolarisDspSource : public AudioSource, public virtual Reporter
{
private:
/**
* The file name of the OSS DSP device (e.g. /dev/audio)
*/
char * fileName;
/**
* The low-level file descriptor of the Solaris DSP device.
*/
int fileDescriptor;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
SolarisDspSource ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @param name the file name of the Solaris DSP device.
* @exception Exception
*/
void
init ( const char * name ) throw ( Exception );
/**
* De-iitialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
public:
/**
* Constructor.
*
* @param name the file name of the Solaris DSP device
* (e.g. /dev/audio or /dev/sound/0)
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channel number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
SolarisDspSource ( const char * name,
int sampleRate = 44100,
int bitsPerSample = 16,
int channel = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channel)
{
init( name);
}
/**
* Copy Constructor.
*
* @param sds the object to copy.
* @exception Exception
*/
inline
SolarisDspSource ( const SolarisDspSource & sds )
throw ( Exception )
: AudioSource( sds )
{
init( sds.fileName);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~SolarisDspSource ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual SolarisDspSource &
operator= ( const SolarisDspSource & ds ) throw ( Exception )
{
if ( this != &ds ) {
strip();
AudioSource::operator=( ds);
init( ds.fileName);
}
return *this;
}
/**
* Tell if the data from this source comes in big or little endian.
*
* @return true
*/
virtual inline bool
isBigEndian ( void ) const throw ()
{
#ifdef WORDS_BIGENDIAN
return true;
#else
return false;
#endif
}
/**
* Open the SolarisDspSource.
* This does not put the Solaris DSP device into recording mode.
* To start getting samples, call either canRead() or read().
*
* @return true if opening was successful, false otherwise
* @exception Exception
*
* @see #canRead
* @see #read
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the SolarisDspSource is open.
*
* @return true if the SolarisDspSource is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return fileDescriptor != 0;
}
/**
* Check if the SolarisDspSource can be read from.
* Blocks until the specified time for data to be available.
* Puts the Solaris DSP device into recording mode.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the SolarisDspSource is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the SolarisDspSource.
* Puts the Solaris DSP device into recording mode.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the SolarisDspSource.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* SOLARIS_DSP_SOURCE_H */

View File

@ -0,0 +1,171 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Source.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef SOURCE_H
#define SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Referable.h"
#include "Exception.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A general data source
*
* @author $Author$
* @version $Revision$
*/
class Source : public virtual Referable
{
private:
protected:
/**
* Default Constructor.
*
* @exception Exception
*/
inline
Source ( void ) throw ( Exception )
{
}
/**
* Copy Constructor.
*
* @param source the object to copy.
* @exception Exception
*/
inline
Source ( const Source & source ) throw ( Exception )
{
}
/**
* Assignment operator.
*
* @param source the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual Source &
operator= ( const Source & source ) throw ( Exception )
{
return *this;
}
public:
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~Source ( void ) throw ( Exception )
{
}
/**
* Open the Source.
*
* @return true if opening was successful, false otherwise
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception ) = 0;
/**
* Check if the Source is open.
*
* @return true if the Source is open, false otherwise.
*/
virtual bool
isOpen ( void ) const throw () = 0;
/**
* Check if the Source can be read from.
* Blocks until the specified time for data to be available.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the Source is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception ) = 0;
/**
* Read from the Source.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception ) = 0;
/**
* Close the Source.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception ) = 0;
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* SOURCE_H */

View File

@ -0,0 +1,418 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : TcpSocket.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#else
#error need errno.h
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#else
#error need sys/socket.h
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#else
#error need netinet/in.h
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#else
#error need netdb.h
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#error need sys/time.h
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#include "Util.h"
#include "Exception.h"
#include "TcpSocket.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
TcpSocket :: init ( const char * host,
unsigned short port ) throw ( Exception )
{
this->host = Util::strDup( host);
this->port = port;
this->sockfd = 0;
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
TcpSocket :: strip ( void) throw ( Exception )
{
if ( isOpen() ) {
close();
}
delete[] host;
}
/*------------------------------------------------------------------------------
* Copy Constructor
*----------------------------------------------------------------------------*/
TcpSocket :: TcpSocket ( const TcpSocket & ss ) throw ( Exception )
: Source( ss), Sink( ss )
{
int fd;
init( ss.host, ss.port);
if ( (fd = ss.sockfd ? dup( ss.sockfd) : 0) == -1 ) {
strip();
throw Exception( __FILE__, __LINE__, "dup failure");
}
sockfd = fd;
}
/*------------------------------------------------------------------------------
* Assignment operator
*----------------------------------------------------------------------------*/
TcpSocket &
TcpSocket :: operator= ( const TcpSocket & ss ) throw ( Exception )
{
if ( this != &ss ) {
int fd;
/* first strip */
strip();
/* then build up */
Sink::operator=( ss );
Source::operator=( ss );
init( ss.host, ss.port);
if ( (fd = ss.sockfd ? dup( ss.sockfd) : 0) == -1 ) {
strip();
throw Exception( __FILE__, __LINE__, "dup failure");
}
sockfd = fd;
}
return *this;
}
/*------------------------------------------------------------------------------
* Open the file
*----------------------------------------------------------------------------*/
bool
TcpSocket :: open ( void ) throw ( Exception )
{
int optval;
socklen_t optlen;
#ifdef HAVE_ADDRINFO
struct addrinfo hints
struct addrinfo * ptr;
struct sockaddr_storage addr;
char portstr[6];
#else
struct sockaddr_in addr;
struct hostent * pHostEntry;
#endif
if ( isOpen() ) {
return false;
}
#ifdef HAVE_ADDRINFO
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_ANY;
snprintf(portstr, sizeof(portstr), "%d", port);
if (getaddrinfo(host , portstr, &hints, &ptr)) {
sockfd = 0;
throw Exception( __FILE__, __LINE__, "getaddrinfo error", errno);
}
memcpy ( addr, ptr->ai_addr, ptr->ai_addrlen);
freeaddrinfo(ptr);
#else
if ( !(pHostEntry = gethostbyname( host)) ) {
sockfd = 0;
throw Exception( __FILE__, __LINE__, "gethostbyname error", errno);
}
memset( &addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *((long*) pHostEntry->h_addr_list[0]);
#endif
if ( (sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
sockfd = 0;
throw Exception( __FILE__, __LINE__, "socket error", errno);
}
// set TCP keep-alive
optval = 1;
optlen = sizeof(optval);
if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) == -1) {
reportEvent(5, "can't set TCP socket keep-alive mode", errno);
}
// connect
if ( connect( sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1 ) {
::close( sockfd);
sockfd = 0;
throw Exception( __FILE__, __LINE__, "connect error", errno);
}
return true;
}
/*------------------------------------------------------------------------------
* Check whether read() would return anything
*----------------------------------------------------------------------------*/
bool
TcpSocket :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
fd_set fdset;
struct timespec timespec;
sigset_t sigset;
int ret;
if ( !isOpen() ) {
return false;
}
FD_ZERO( &fdset);
FD_SET( sockfd, &fdset);
timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( sockfd + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) {
::close( sockfd);
sockfd = 0;
throw Exception( __FILE__, __LINE__, "select error");
}
return ret > 0;
}
/*------------------------------------------------------------------------------
* Read from the socket
*----------------------------------------------------------------------------*/
unsigned int
TcpSocket :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
int ret;
if ( !isOpen() ) {
return 0;
}
ret = recv( sockfd, buf, len, 0);
if ( ret == -1 ) {
switch (errno) {
case ECONNRESET:
// re-open the socket if it has been reset by the peer
close();
Util::sleep(1L, 0L);
open();
break;
default:
::close( sockfd);
sockfd = 0;
throw Exception( __FILE__, __LINE__, "recv error", errno);
}
}
return ret;
}
/*------------------------------------------------------------------------------
* Check whether write() would send anything
*----------------------------------------------------------------------------*/
bool
TcpSocket :: canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
fd_set fdset;
struct timespec timespec;
sigset_t sigset;
int ret;
if ( !isOpen() ) {
return false;
}
FD_ZERO( &fdset);
FD_SET( sockfd, &fdset);
timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( sockfd + 1, NULL, &fdset, NULL, &timespec, &sigset);
if ( ret == -1 ) {
::close( sockfd);
sockfd = 0;
reportEvent(4,"TcpSocket :: canWrite, connection lost", errno);
}
return ret > 0;
}
/*------------------------------------------------------------------------------
* Write to the socket
*----------------------------------------------------------------------------*/
unsigned int
TcpSocket :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
int ret;
if ( !isOpen() ) {
return 0;
}
#ifdef HAVE_MSG_NOSIGNAL
ret = send( sockfd, buf, len, MSG_NOSIGNAL);
#else
ret = send( sockfd, buf, len, 0);
#endif
if ( ret == -1 ) {
if ( errno == EAGAIN ) {
ret = 0;
} else {
::close( sockfd);
sockfd = 0;
reportEvent(4,"TcpSocket :: write, send error", errno);
throw Exception( __FILE__, __LINE__, "send error", errno);
}
}
return ret;
}
/*------------------------------------------------------------------------------
* Close the socket
*----------------------------------------------------------------------------*/
void
TcpSocket :: close ( void ) throw ( Exception )
{
if ( !isOpen() ) {
return;
}
flush();
::close( sockfd);
sockfd = 0;
}

View File

@ -0,0 +1,292 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : TcpSocket.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef TCP_SOCKET_H
#define TCP_SOCKET_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Source.h"
#include "Sink.h"
#include "Reporter.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A TCP network socket
*
* @author $Author$
* @version $Revision$
*/
class TcpSocket : public Source, public Sink, public virtual Reporter
{
private:
/**
* Name of the host this socket connects to.
*/
char * host;
/**
* Port to connect to.
*/
unsigned short port;
/**
* Low-level socket descriptor.
*/
int sockfd;
/**
* Initialize the object.
*
* @param host name of the host this socket connects to.
* @param port port to connect to.
* @exception Exception
*/
void
init ( const char * host,
unsigned short port ) throw ( Exception );
/**
* De-initialize the object.
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
TcpSocket ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor.
*
* @param host name of the host this socket connects to.
* @param port port to connect to.
* @exception Exception
*/
inline
TcpSocket( const char * host,
unsigned short port ) throw ( Exception )
{
init( host, port);
}
/**
* Copy constructor.
*
* @param ss the TcpSocket to copy.
* @exception Exception
*/
TcpSocket( const TcpSocket & ss ) throw ( Exception );
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~TcpSocket( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ss the TcpSocket to assign this to.
* @return a reference to this TcpSocket.
* @exception Exception
*/
inline virtual TcpSocket &
operator= ( const TcpSocket & ss ) throw ( Exception );
/**
* Get the host this socket connects to.
*
* @return the host this socket connects to.
*/
inline const char *
getHost ( void ) const throw ()
{
return host;
}
/**
* Get the port this socket connects to.
*
* @return the port this socket connects to.
*/
inline unsigned int
getPort ( void ) const throw ()
{
return port;
}
/**
* Open the TcpSocket.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the TcpSocket is open.
*
* @return true if the TcpSocket is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return sockfd != 0;
}
/**
* Check if the TcpScoket can be read from.
* Blocks until the specified time for data to be available.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the TcpSocket is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the TcpSocket.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Check if the TcpSocket is ready to accept data.
* Blocks until the specified time for data to be available.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the TcpSocket is ready to accept data,
* false otherwise.
* @exception Exception
*/
virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Write data to the TcpSocket.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* Flush all data that was written to the TcpSocket to the underlying
* connection.
*
* @exception Exception
*/
inline virtual void
flush ( void ) throw ( Exception )
{
}
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*
* For TcpSocket, this is a no-op.
*/
inline virtual void
cut ( void ) throw ()
{
}
/**
* Close the TcpSocket.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* TCP_SOCKET_H */

View File

@ -0,0 +1,301 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : TwoLameLibEncoder.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// compile the whole file only if TwoLame support configured in
#ifdef HAVE_TWOLAME_LIB
#include "Exception.h"
#include "Util.h"
#include "TwoLameLibEncoder.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
TwoLameLibEncoder :: init ( void ) throw ( Exception )
{
this->twolame_opts = NULL;
if ( getInBitsPerSample() != 16 ) {
throw Exception( __FILE__, __LINE__,
"specified bits per sample not supported",
getInBitsPerSample() );
}
if ( getInChannel() != 1 && getInChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of input channels for the encoder",
getInChannel() );
}
if ( getOutChannel() != 1 && getOutChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of output channels for the encoder",
getOutChannel() );
}
if ( getInChannel() < getOutChannel() ) {
throw Exception( __FILE__, __LINE__,
"output channels greater then input channels",
getOutChannel() );
}
}
/*------------------------------------------------------------------------------
* Open an encoding session
*----------------------------------------------------------------------------*/
bool
TwoLameLibEncoder :: open ( void )
throw ( Exception )
{
if ( isOpen() ) {
close();
}
// open the underlying sink
if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__,
"TwoLAME lib opening underlying sink error");
}
twolame_opts = ::twolame_init();
// ugly twolame returns -1 in a pointer on allocation errors
if ( !twolame_opts ) {
throw Exception( __FILE__, __LINE__,
"TwoLAME lib init error",
(long int) twolame_opts);
}
if ( 0 > twolame_set_num_channels( twolame_opts, getInChannel()) ) {
throw Exception( __FILE__, __LINE__,
"TwoLAME lib setting channels error",
getInChannel() );
}
if ( 0 > twolame_set_mode( twolame_opts,
getOutChannel() == 1 ? TWOLAME_MONO : TWOLAME_JOINT_STEREO) ) {
throw Exception( __FILE__, __LINE__,
"TwoLAME lib setting mode error",
TWOLAME_JOINT_STEREO );
}
if ( 0 > twolame_set_in_samplerate( twolame_opts, getInSampleRate()) ) {
throw Exception( __FILE__, __LINE__,
"TwoLAME lib setting input sample rate error",
getInSampleRate() );
}
if ( 0 > twolame_set_out_samplerate( twolame_opts, getOutSampleRate()) ) {
throw Exception( __FILE__, __LINE__,
"TwoLAME lib setting output sample rate error",
getOutSampleRate() );
}
switch ( getOutBitrateMode() ) {
case cbr: {
if ( 0 > twolame_set_brate( twolame_opts, getOutBitrate()) ) {
throw Exception( __FILE__, __LINE__,
"TwoLAME lib setting output bit rate error",
getOutBitrate() );
}
} break;
default: {
throw Exception( __FILE__, __LINE__,
"Unsupported bitrate mode." );
}
}
// let TwoLAME init its own params based on our settings
if ( 0 > twolame_init_params( twolame_opts) ) {
throw Exception( __FILE__, __LINE__,
"TwoLAME lib initializing params error" );
}
// Information about TwoLame's setup
if (getReportVerbosity() >= 3) {
twolame_print_config( twolame_opts);
}
return true;
}
/*------------------------------------------------------------------------------
* Write data to the encoder
*----------------------------------------------------------------------------*/
unsigned int
TwoLameLibEncoder :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
if ( !isOpen() || len == 0 ) {
return 0;
}
unsigned int bitsPerSample = getInBitsPerSample();
unsigned int inChannels = getInChannel();
unsigned int sampleSize = (bitsPerSample / 8) * inChannels;
unsigned char * b = (unsigned char*) buf;
unsigned int processed = len - (len % sampleSize);
unsigned int nSamples = processed / sampleSize;
short int * leftBuffer = new short int[nSamples];
short int * rightBuffer = new short int[nSamples];
if ( bitsPerSample == 8 ) {
Util::conv8( b, processed, leftBuffer, rightBuffer, inChannels);
} else if ( bitsPerSample == 16 ) {
Util::conv16( b,
processed,
leftBuffer,
rightBuffer,
inChannels,
isInBigEndian());
} else {
delete[] leftBuffer;
delete[] rightBuffer;
throw Exception( __FILE__, __LINE__,
"unsupported number of bits per sample for the encoder",
bitsPerSample );
}
// data chunk size estimate according to TwoLAME documentation
// NOTE: mp2Size is calculated based on the number of input channels
// which may be bigger than need, as output channels can be less
unsigned int mp2Size = (unsigned int) (1.25 * nSamples + 7200);
unsigned char * mp2Buf = new unsigned char[mp2Size];
int ret;
ret = twolame_encode_buffer( twolame_opts,
leftBuffer,
inChannels == 2 ? rightBuffer : leftBuffer,
nSamples,
mp2Buf,
mp2Size );
delete[] leftBuffer;
delete[] rightBuffer;
if ( ret < 0 ) {
reportEvent( 3, "TwoLAME encoding error", ret);
delete[] mp2Buf;
return 0;
}
unsigned int written = getSink()->write( mp2Buf, ret);
delete[] mp2Buf;
// just let go data that could not be written
if ( written < (unsigned int) ret ) {
reportEvent( 2,
"couldn't write all from encoder to underlying sink",
ret - written);
}
return processed;
}
/*------------------------------------------------------------------------------
* Flush the data from the encoder
*----------------------------------------------------------------------------*/
void
TwoLameLibEncoder :: flush ( void )
throw ( Exception )
{
if ( !isOpen() ) {
return;
}
// data chunk size estimate according to TwoLAME documentation
unsigned int mp2Size = 7200;
unsigned char * mp2Buf = new unsigned char[mp2Size];
int ret;
ret = twolame_encode_flush( twolame_opts, mp2Buf, mp2Size );
unsigned int written = getSink()->write( mp2Buf, ret);
delete[] mp2Buf;
// just let go data that could not be written
if ( written < (unsigned int) ret ) {
reportEvent( 2,
"couldn't write all from encoder to underlying sink",
ret - written);
}
getSink()->flush();
}
/*------------------------------------------------------------------------------
* Close the encoding session
*----------------------------------------------------------------------------*/
void
TwoLameLibEncoder :: close ( void ) throw ( Exception )
{
if ( isOpen() ) {
flush();
twolame_close( &twolame_opts );
getSink()->close();
}
}
#endif // HAVE_TWOLAME_LIB

View File

@ -0,0 +1,367 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : TwoLameLibEncoder.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef TWOLAME_LIB_ENCODER_H
#define TWOLAME_LIB_ENCODER_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_TWOLAME_LIB
#include <twolame.h>
#else
#error configure with twolame
#endif
#include "Ref.h"
#include "Exception.h"
#include "Reporter.h"
#include "AudioEncoder.h"
#include "Sink.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A class representing the TwoLame encoder linked as a shared object or as
* a static library.
*
* @author $Author$
* @version $Revision$
*/
class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter
{
private:
/**
* TwoLame library global flags
*/
twolame_options * twolame_opts;
/**
* Initialize the object.
*
* @param sink the sink to send mp2 output to
* @exception Exception
*/
void
init ( void ) throw ( Exception );
/**
* De-initialize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
}
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
TwoLameLibEncoder ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor.
*
* @param sink the sink to send mp2 output to
* @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input.
* @param inBigEndian shows if the input is big or little endian
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outSampleRate sample rate of the output.
* If 0, inSampleRate is used.
* @param outChannel number of channels of the output.
* If 0, inChannel is used.
* @exception Exception
*/
inline
TwoLameLibEncoder ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample,
unsigned int inChannel,
bool inBigEndian,
BitrateMode outBitrateMode,
unsigned int outBitrate,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0 )
throw ( Exception )
: AudioEncoder ( sink,
inSampleRate,
inBitsPerSample,
inChannel,
inBigEndian,
outBitrateMode,
outBitrate,
0.0f, // outQuality
outSampleRate,
outChannel )
{
init();
}
/**
* Constructor.
*
* @param sink the sink to send mp2 output to
* @param as get input sample rate, bits per sample and channels
* from this AudioSource.
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outSampleRate sample rate of the output.
* If 0, input sample rate is used.
* @param outChannel number of channels of the output.
* If 0, input channel is used.
* @exception Exception
*/
inline
TwoLameLibEncoder ( Sink * sink,
const AudioSource * as,
BitrateMode outBitrateMode,
unsigned int outBitrate,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0 )
throw ( Exception )
: AudioEncoder ( sink,
as,
outBitrateMode,
outBitrate,
0.0f, // outQuality
outSampleRate,
outChannel )
{
init();
}
/**
* Copy constructor.
*
* @param encoder the TwoLameLibEncoder to copy.
*/
inline
TwoLameLibEncoder ( const TwoLameLibEncoder & encoder )
throw ( Exception )
: AudioEncoder( encoder )
{
init();
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~TwoLameLibEncoder ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
strip();
}
/**
* Assignment operator.
*
* @param encoder the TwoLameLibEncoder to assign this to.
* @return a reference to this TwoLameLibEncoder.
* @exception Exception
*/
inline virtual TwoLameLibEncoder &
operator= ( const TwoLameLibEncoder & encoder ) throw ( Exception )
{
if ( this != &encoder ) {
strip();
AudioEncoder::operator=( encoder);
init();
}
return *this;
}
/**
* Get the version string of the underlying lame library.
*
* @return the version string of the underlying lame library.
*/
inline const char *
getLameVersion( void )
{
return get_twolame_version();
}
/**
* Check whether encoding is in progress.
*
* @return true if encoding is in progress, false otherwise.
*/
inline virtual bool
isRunning ( void ) const throw ()
{
return isOpen();
}
/**
* Start encoding. This function returns as soon as possible,
* with encoding started in the background.
*
* @return true if encoding has started, false otherwise.
* @exception Exception
*/
inline virtual bool
start ( void ) throw ( Exception )
{
return open();
}
/**
* Stop encoding. Stops the encoding running in the background.
*
* @exception Exception
*/
inline virtual void
stop ( void ) throw ( Exception )
{
return close();
}
/**
* Open an encoding session.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the encoding session is open.
*
* @return true if the encoding session is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return twolame_opts != 0;
}
/**
* Check if the encoder is ready to accept data.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the encoder is ready to accept data,
* false otherwise.
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
if ( !isOpen() ) {
return false;
}
return true;
}
/**
* Write data to the encoder.
* Buf is expected to be a sequence of big-endian 16 bit values,
* with left and right channels interleaved. Len is the number of
* bytes, must be a multiple of 4.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* Flush all data that was written to the encoder to the underlying
* connection.
*
* @exception Exception
*/
virtual void
flush ( void ) throw ( Exception );
/**
* Close the encoding session.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* TWOLAME_LIB_ENCODER_H */

View File

@ -0,0 +1,540 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Util.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#else
#error need errno.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
#error need stdlib.h
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#else
#error need limits.h
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#else
#error need math.h
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#else
#error need time.h
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#error need sys/time.h
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include "Util.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
char
Util :: base64Table[] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};
/*------------------------------------------------------------------------------
* Calculate the length of a zero-terminated C string,
* w/o the zero-termination
*----------------------------------------------------------------------------*/
unsigned int
Util :: strLen( const char * str ) throw ( Exception )
{
size_t len;
if ( !str ) {
throw Exception( __FILE__, __LINE__, "no str");
}
len = strlen( str);
return len;
}
/*------------------------------------------------------------------------------
* Copy the contents of a string into another
*----------------------------------------------------------------------------*/
void
Util :: strCpy ( char * dest,
const char * src ) throw ( Exception )
{
if ( !dest || !src ) {
throw Exception( __FILE__, __LINE__, "no src or dest");
}
strcpy( dest, src);
}
/*------------------------------------------------------------------------------
* Concatenate the contents of a string onto another
*----------------------------------------------------------------------------*/
void
Util :: strCat ( char * dest,
const char * src ) throw ( Exception )
{
if ( !dest || !src ) {
throw Exception( __FILE__, __LINE__, "no src or dest");
}
strcat( dest, src);
}
/*------------------------------------------------------------------------------
* Duplicate a string by allocating space with new[]
* The returned string must be freed with delete[]
*----------------------------------------------------------------------------*/
char *
Util :: strDup( const char * str ) throw ( Exception )
{
size_t len;
char * s;
if ( !str ) {
throw Exception( __FILE__, __LINE__, "no str");
}
len = strlen( str) + 1;
s = new char[len];
memcpy( s, str, len);
return s;
}
/*------------------------------------------------------------------------------
* Convert a string into base64 encoding.
*----------------------------------------------------------------------------*/
char *
Util :: base64Encode( const char * str ) throw ( Exception )
{
if ( !str ) {
throw Exception( __FILE__, __LINE__, "no str");
}
const char * data = str;
size_t len = strlen( data);
char * out = new char[len * 4 / 3 + 4];
char * result = out;
unsigned chunk;
while ( len > 0 ) {
chunk = (len > 3) ? 3 : len;
*out++ = base64Table[(*data & 0xfc) >> 2];
*out++ = base64Table[((*data & 0x03) << 4) | ((*(data+1) & 0xf0) >> 4)];
switch ( chunk ) {
case 3:
*out++ = base64Table[((*(data+1) & 0x0f) << 2) |
((*(data+2) & 0xc0) >> 6)];
*out++ = base64Table[(*(data+2)) & 0x3f];
break;
case 2:
*out++ = base64Table[((*(data+1) & 0x0f) << 2)];
*out++ = '=';
break;
case 1:
*out++ = '=';
*out++ = '=';
break;
}
data += chunk;
len -= chunk;
}
*out = 0;
return result;
}
/*------------------------------------------------------------------------------
* Check whether two strings are equal
*----------------------------------------------------------------------------*/
bool
Util :: strEq( const char * str1,
const char * str2,
unsigned int len ) throw ( Exception )
{
if ( !str1 || !str2 ) {
throw Exception( __FILE__, __LINE__, "no str1 or no str2");
}
return len == 0 ? !strcmp( str1, str2) : !strncmp( str1, str2, len);
}
/*------------------------------------------------------------------------------
* Convert a string to a long integer
*----------------------------------------------------------------------------*/
long int
Util :: strToL( const char *str) throw ( Exception )
{
long int val;
char *end;
if ( NULL == str )
throw Exception( __FILE__, __LINE__, "null pointer parameter, not string");
errno = 0; // set it, strtol() can change it
val = strtol( str, &end, 10);
if (end == str)
throw Exception( __FILE__, __LINE__, "number conversion error, not a decimal string");
if ((LONG_MIN == val || LONG_MAX == val) && ERANGE == errno)
throw Exception( __FILE__, __LINE__, "number conversion error, out of range of type long");
return val;
}
/*------------------------------------------------------------------------------
* Convert a string to a double
*----------------------------------------------------------------------------*/
double
Util :: strToD( const char * str ) throw ( Exception )
{
double val;
char * s;
if ( !str ) {
throw Exception( __FILE__, __LINE__, "no str");
}
val = strtod( str, &s);
if ( s == str || errno == ERANGE ) {
throw Exception( __FILE__, __LINE__, "number conversion error");
}
return val;
}
/*------------------------------------------------------------------------------
* add current date to a file name, before the file extension (if any)
*----------------------------------------------------------------------------*/
char *
Util :: fileAddDate ( const char * str,
const char * format ) throw ( Exception )
{
unsigned int size;
const char * last;
char * s;
char * strdate;
time_t now;
if ( !str ) {
throw Exception( __FILE__, __LINE__, "no str");
}
strdate = new char[128];
now = time(NULL);
strftime( strdate, 128, format, localtime (&now));
// search for the part before the extension of the file name
if ( !(last = strrchr( str, '.')) ) {
last = (char *) str + strlen( str);
}
size = strlen( str) + strlen( strdate) + 1;
s = new char [size];
memcpy( s, str, strlen (str)-strlen(last));
memcpy( s + strlen(str) - strlen(last), strdate, strlen (strdate));
memcpy( s + strlen(str) - strlen(last) + strlen(strdate),
last,
strlen(last));
s[size-1] = '\0';
delete[] strdate;
return s;
}
/*------------------------------------------------------------------------------
* Convert an unsigned char buffer holding 8 or 16 bit PCM values with
* channels interleaved to a short int buffer, still with channels interleaved
*----------------------------------------------------------------------------*/
void
Util :: conv ( unsigned int bitsPerSample,
unsigned char * pcmBuffer,
unsigned int lenPcmBuffer,
short int * outBuffer,
bool isBigEndian ) throw ( Exception )
{
if ( bitsPerSample == 8 ) {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
outBuffer[j] = pcmBuffer[i++];
++j;
}
} else if ( bitsPerSample == 16 ) {
if ( isBigEndian ) {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
short int value;
value = pcmBuffer[i++] << 8;
value |= pcmBuffer[i++];
outBuffer[j] = value;
++j;
}
} else {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
short int value;
value = pcmBuffer[i++];
value |= pcmBuffer[i++] << 8;
outBuffer[j] = value;
++j;
}
}
} else {
throw Exception( __FILE__, __LINE__,
"this number of bits per sample not supported",
bitsPerSample);
}
}
/*------------------------------------------------------------------------------
* Convert a short buffer holding PCM values with channels interleaved
* to one or more float buffers, one for each channel
*----------------------------------------------------------------------------*/
void
Util :: conv ( short int * shortBuffer,
unsigned int lenShortBuffer,
float ** floatBuffers,
unsigned int channels ) throw ( Exception )
{
unsigned int i, j;
for ( i = 0, j = 0; i < lenShortBuffer; ) {
for ( unsigned int c = 0; c < channels; ++c ) {
floatBuffers[c][j] = ((float) shortBuffer[i++]) / 32768.f;
}
++j;
}
}
/*------------------------------------------------------------------------------
* Convert an unsigned char buffer holding 8 bit PCM values with channels
* interleaved to two short int buffers (one for each channel)
*----------------------------------------------------------------------------*/
void
Util :: conv8 ( unsigned char * pcmBuffer,
unsigned int lenPcmBuffer,
short int * leftBuffer,
short int * rightBuffer,
unsigned int channels ) throw ( Exception )
{
if ( channels == 1 ) {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
unsigned short int value;
value = pcmBuffer[i++];
leftBuffer[j] = (short int) value;
++j;
}
} else if ( channels == 2 ) {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
unsigned short int value;
value = pcmBuffer[i++];
leftBuffer[j] = (short int) value;
value = pcmBuffer[i++];
rightBuffer[j] = (short int) value;
++j;
}
} else {
throw Exception( __FILE__, __LINE__,
"this number of channels not supported", channels);
}
}
/*------------------------------------------------------------------------------
* Convert an unsigned char buffer holding 16 bit PCM values with channels
* interleaved to two short int buffers (one for each channel)
*----------------------------------------------------------------------------*/
void
Util :: conv16 ( unsigned char * pcmBuffer,
unsigned int lenPcmBuffer,
short int * leftBuffer,
short int * rightBuffer,
unsigned int channels,
bool isBigEndian ) throw ( Exception )
{
if ( isBigEndian ) {
if ( channels == 1 ) {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
unsigned short int value;
value = pcmBuffer[i++] << 8;
value |= pcmBuffer[i++];
leftBuffer[j] = (short int) value;
++j;
}
} else {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
unsigned short int value;
value = pcmBuffer[i++] << 8;
value |= pcmBuffer[i++];
leftBuffer[j] = (short int) value;
value = pcmBuffer[i++] << 8;
value |= pcmBuffer[i++];
rightBuffer[j] = (short int) value;
++j;
}
}
} else {
if ( channels == 1 ) {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
unsigned short int value;
value = pcmBuffer[i++];
value |= pcmBuffer[i++] << 8;
leftBuffer[j] = (short int) value;
++j;
}
} else {
unsigned int i, j;
for ( i = 0, j = 0; i < lenPcmBuffer; ) {
unsigned short int value;
value = pcmBuffer[i++];
value |= pcmBuffer[i++] << 8;
leftBuffer[j] = (short int) value;
value = pcmBuffer[i++];
value |= pcmBuffer[i++] << 8;
rightBuffer[j] = (short int) value;
++j;
}
}
}
}
/*------------------------------------------------------------------------------
* Make a thread sleep for a specified amount of time.
*----------------------------------------------------------------------------*/
void
Util :: sleep ( long sec,
long nsec)
{
struct timespec timespec;
sigset_t sigset;
timespec.tv_sec = sec;
timespec.tv_nsec = nsec;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
pselect( 0, NULL, NULL, NULL, &timespec, &sigset);
}

View File

@ -0,0 +1,330 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : Util.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef UTIL_H
#define UTIL_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Exception.h"
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* Widely used utilities.
* This class can not be instantiated, but contains useful (?) static
* functions.
*
* Typical usage:
*
* <pre>
* #include "Util.h"
*
* char * str = Util::strDup( otherStr);
* </pre>
*
* @author $Author$
* @version $Revision$
*/
class Util
{
private:
/**
* Helper table for base64 encoding.
*/
static char base64Table[];
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
Util ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Copy constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
Util ( const Util & e ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Destructor. Always throws an Exception.
*
* @exception Exception
*/
inline
~Util ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Assignment operator. Always throws an Exception.
*
* @param u the object to assign to this one.
* @exception Exception
*/
inline Util &
operator= ( const Util & u ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Determine a C string's length.
*
* @param str a zero-terminated C string.
* @return length of str
* @exception Exception
*/
static unsigned int
strLen ( const char * str ) throw ( Exception );
/**
* Copy a C string into another.
*
* @param dest place for the copy. Storage size must be at least
* Util::strLen(src) + 1 long.
* @param src the string to copy.
* @exception Exception
*/
static void
strCpy ( char * dest,
const char * src ) throw ( Exception );
/**
* Concatenate a string to another's end.
*
* @param dest the string to concatenate to.
* Storage size of dest must be at least
* Util::strLen(dest) + Util::strLen(src) + 1 long.
* @param src the string to concatenate.
* @exception Exception
*/
static void
strCat ( char * dest,
const char * src ) throw ( Exception );
/**
* Duplicate a string by allocating space with new[].
* The returned string must be freed with delete[].
*
* @param str the string to duplicate.
* @exception Exception
*/
static char *
strDup ( const char * str ) throw ( Exception );
/**
* Determine whether two string are equal.
*
* @param str1 one of the strings.
* @param str2 the other string.
* @param len check the first most len characters. if 0, check
* the whole string
* @return true if the two strings are equal, false othersize.
* @exception Exception
*/
static bool
strEq ( const char * str1,
const char * str2,
unsigned int len = 0 ) throw ( Exception );
/**
* Convert a string to long.
*
* @param str the string to convert.
* @return the value of str as a long int
* @exception Exception
*/
static long int
strToL ( const char * str) throw ( Exception );
/**
* Convert a string to double.
*
* @param str the string to convert.
* @return the value of str as a double
* @exception Exception
*/
static double
strToD ( const char * str ) throw ( Exception );
/**
* Add current date to a file name, before the file extension (if any)
*
* @param str the string to convert (file name).
* @return the new string with the date appended before
* extension of the file name. the string has to be
* deleted with delete[] after it is not needed
* @exception Exception
*/
static char *
fileAddDate ( const char * str,
const char * format = "[%m-%d-%Y-%H-%M-%S]" )
throw ( Exception );
/**
* Convert a string into base64 encoding.
* base64 is described in RFC 2045, section 6.8
* The returned string must be freed with delete[].
*
* @param str the string to convert.
* @return the supplied string in base64 encoding.
* @exception Exception
*/
static char *
base64Encode ( const char * str ) throw ( Exception );
/**
* Convert an unsigned char buffer holding 8 or 16 bit PCM values
* with channels interleaved to a short int buffer, still
* with channels interleaved.
*
* @param bitsPerSample the number of bits per sample in the input
* @param pcmBuffer the input buffer
* @param lenPcmBuffer the number of samples total in pcmBuffer
* (e.g. if 2 channel input, this is twice the
* number of sound samples)
* @param outBuffer the output buffer, must be big enough
* @param isBigEndian true if the input is big endian, false otherwise
*/
static void
conv ( unsigned int bitsPerSample,
unsigned char * pcmBuffer,
unsigned int lenPcmBuffer,
short int * outBuffer,
bool isBigEndian = true ) throw ( Exception );
/**
* Convert a short buffer holding PCM values with channels interleaved
* to one or more float buffers, one for each channel
*
* @param shortBuffer the input buffer
* @param lenShortBuffer total length of the input buffer
* @param floatBuffers an array of float buffers, each
* (lenShortBuffer / channels) long
* @param channels number of channels to separate the input to
*/
static void
conv ( short int * shortBuffer,
unsigned int lenShortBuffer,
float ** floatBuffers,
unsigned int channels ) throw ( Exception );
/**
* Convert a char buffer holding 8 bit PCM values to a short buffer
*
* @param pcmBuffer buffer holding 8 bit PCM audio values,
* channels are interleaved
* @param lenPcmBuffer length of pcmBuffer
* @param leftBuffer put the left channel here (must be big enough)
* @param rightBuffer put the right channel here (not touched if mono,
* must be big enough)
* @param channels number of channels (1 = mono, 2 = stereo)
*/
static void
conv8 ( unsigned char * pcmBuffer,
unsigned int lenPcmBuffer,
short int * leftBuffer,
short int * rightBuffer,
unsigned int channels ) throw ( Exception );
/**
* Convert a char buffer holding 16 bit PCM values to a short buffer
*
* @param pcmBuffer buffer holding 16 bit PCM audio values,
* channels are interleaved
* @param lenPcmBuffer length of pcmBuffer
* @param leftBuffer put the left channel here (must be big enough)
* @param rightBuffer put the right channel here (not touched if mono,
* must be big enough)
* @param channels number of channels (1 = mono, 2 = stereo)
* @param isBigEndian true if input is big endian, false otherwise
*/
static void
conv16 ( unsigned char * pcmBuffer,
unsigned int lenPcmBuffer,
short int * leftBuffer,
short int * rightBuffer,
unsigned int channels,
bool isBigEndian ) throw ( Exception );
/**
* Make a thread sleep for specified amount of time.
* Only the thread which this is called in will sleep.
* The SIGUSR1 signal will be blocked during the sleep.
*
* @param sec the number of seconds to sleep.
* @param nsec the number of nano-seconds to sleep.
*/
static void
sleep( long sec,
long nsec);
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* UTIL_H */

View File

@ -0,0 +1,455 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : VorbisLibEncoder.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// compile only if configured for Ogg Vorbis
#ifdef HAVE_VORBIS_LIB
#include "Exception.h"
#include "Util.h"
#include "VorbisLibEncoder.h"
#define VORBIS_MIN_BITRATE 45
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the encoder
*----------------------------------------------------------------------------*/
void
VorbisLibEncoder :: init ( unsigned int outMaxBitrate )
throw ( Exception )
{
this->outMaxBitrate = outMaxBitrate;
if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) {
throw Exception( __FILE__, __LINE__,
"specified bits per sample not supported",
getInBitsPerSample() );
}
if ( getInChannel() != 1 && getInChannel() != 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of channels for the encoder",
getInChannel() );
}
if ( getOutBitrateMode() == abr || getOutBitrateMode() == cbr ) {
if ( getOutBitrate() < VORBIS_MIN_BITRATE ) {
throw Exception( __FILE__, __LINE__,
"output bitrate is lower than libvorbis minimum",
getOutBitrate() );
}
}
if ( getOutSampleRate() == getInSampleRate() ) {
resampleRatio = 1;
converter = 0;
} else {
resampleRatio = ( (double) getOutSampleRate() /
(double) getInSampleRate() );
// Determine if we can use linear interpolation.
// The inverse of the ratio must be a power of two for linear mode to
// be of sufficient quality.
bool useLinear = true;
double inverse = 1 / resampleRatio;
int integer = (int) inverse;
// Check that the inverse of the ratio is an integer
if( integer == inverse ) {
while( useLinear && integer ) { // Loop through the bits
// If the lowest order bit is not the only one set
if( integer & 1 && integer != 1 ) {
// Not a power of two; cannot use linear
useLinear = false;
} else {
// Shift all the bits over and try again
integer >>= 1;
}
}
} else {
useLinear = false;
}
// If we get here and useLinear is still true, then we have
// a power of two.
// open the aflibConverter in
// - high quality
// - linear or quadratic (non-linear) based on algorithm
// - not filter interpolation
#ifdef HAVE_SRC_LIB
int srcError = 0;
converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST,
getInChannel(), &srcError);
if(srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
#else
converter = new aflibConverter( true, useLinear, false);
#endif
}
encoderOpen = false;
}
/*------------------------------------------------------------------------------
* Open an encoding session
*----------------------------------------------------------------------------*/
bool
VorbisLibEncoder :: open ( void )
throw ( Exception )
{
int ret;
if ( isOpen() ) {
close();
}
// open the underlying sink
if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__,
"vorbis lib opening underlying sink error");
}
vorbis_info_init( &vorbisInfo);
switch ( getOutBitrateMode() ) {
case cbr: {
int maxBitrate = getOutMaxBitrate() * 1000;
if ( !maxBitrate ) {
maxBitrate = -1;
}
if ( (ret = vorbis_encode_init( &vorbisInfo,
getOutChannel(),
getOutSampleRate(),
maxBitrate,
getOutBitrate() * 1000,
-1)) ) {
throw Exception( __FILE__, __LINE__,
"vorbis encode init error", ret);
}
} break;
case abr:
/* set non-managed VBR around the average bitrate */
ret = vorbis_encode_setup_managed( &vorbisInfo,
getOutChannel(),
getOutSampleRate(),
-1,
getOutBitrate() * 1000,
-1 )
|| vorbis_encode_ctl( &vorbisInfo, OV_ECTL_RATEMANAGE_SET, NULL)
|| vorbis_encode_setup_init( &vorbisInfo);
if ( ret ) {
throw Exception( __FILE__, __LINE__,
"vorbis encode init error", ret);
}
break;
case vbr:
if ( (ret = vorbis_encode_init_vbr( &vorbisInfo,
getOutChannel(),
getOutSampleRate(),
getOutQuality() )) ) {
throw Exception( __FILE__, __LINE__,
"vorbis encode init error", ret);
}
break;
}
if ( (ret = vorbis_analysis_init( &vorbisDspState, &vorbisInfo)) ) {
throw Exception( __FILE__, __LINE__, "vorbis analysis init error", ret);
}
if ( (ret = vorbis_block_init( &vorbisDspState, &vorbisBlock)) ) {
throw Exception( __FILE__, __LINE__, "vorbis block init error", ret);
}
if ( (ret = ogg_stream_init( &oggStreamState, 0)) ) {
throw Exception( __FILE__, __LINE__, "ogg stream init error", ret);
}
// create an empty vorbis_comment structure
vorbis_comment_init( &vorbisComment);
/* FIXME: removed title metadata when the sink type was changed from
* CastSink to the more generic Sink.
* make sure to add metadata somehow
// Add comment to vorbis headers to show title in players
// stupid cast to (char*) because of stupid vorbis API
if ( getSink()->getName() ) {
vorbis_comment_add_tag(&vorbisComment,
"TITLE",
(char*) getSink()->getName());
}
*/
// create the vorbis stream headers and send them to the underlying sink
ogg_packet header;
ogg_packet commentHeader;
ogg_packet codeHeader;
if ( (ret = vorbis_analysis_headerout( &vorbisDspState,
&vorbisComment,
&header,
&commentHeader,
&codeHeader )) ) {
throw Exception( __FILE__, __LINE__, "vorbis header init error", ret);
}
ogg_stream_packetin( &oggStreamState, &header);
ogg_stream_packetin( &oggStreamState, &commentHeader);
ogg_stream_packetin( &oggStreamState, &codeHeader);
ogg_page oggPage;
while ( ogg_stream_flush( &oggStreamState, &oggPage) ) {
getSink()->write( oggPage.header, oggPage.header_len);
getSink()->write( oggPage.body, oggPage.body_len);
}
vorbis_comment_clear( &vorbisComment );
// initialize the resampling coverter if needed
if ( converter ) {
#ifdef HAVE_SRC_LIB
converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel());
converterData.data_in = new float[converterData.input_frames*getInChannel()];
converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1);
converterData.data_out = new float[getInChannel() * converterData.output_frames];
converterData.src_ratio = resampleRatio;
converterData.end_of_input = 0;
#else
converter->initialize( resampleRatio, getInChannel());
#endif
}
encoderOpen = true;
return true;
}
/*------------------------------------------------------------------------------
* Write data to the encoder
*----------------------------------------------------------------------------*/
unsigned int
VorbisLibEncoder :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
if ( !isOpen() || len == 0 ) {
return 0;
}
unsigned int channels = getInChannel();
unsigned int bitsPerSample = getInBitsPerSample();
unsigned int sampleSize = (bitsPerSample / 8) * channels;
unsigned int i;
if ( getInChannel() == 2 && getOutChannel() == 1 ) {
for ( i = 0; i < len/sampleSize; i++) {
if ( bitsPerSample == 8 ) {
char * buf8 = (char *) buf;
unsigned int ix = sampleSize * i;
unsigned int iix = ix;
buf8[i] = (buf8[ix] + buf8[++iix]) / 2;
}
if ( bitsPerSample == 16 ) {
short * buf16 = (short *) buf;
unsigned int ix = (bitsPerSample >> 3) * i;
unsigned int iix = ix;
buf16[i] = (buf16[ix] + buf16[++iix]) / 2;
}
}
len >>= 1;
channels = 1;
}
sampleSize = (bitsPerSample / 8) * channels;
unsigned char * b = (unsigned char*) buf;
unsigned int processed = len - (len % sampleSize);
unsigned int nSamples = processed / sampleSize;
float ** vorbisBuffer;
// convert the byte-based raw input into a short buffer
// with channels still interleaved
unsigned int totalSamples = nSamples * channels;
short int * shortBuffer = new short int[totalSamples];
Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian());
if ( converter ) {
// resample if needed
int inCount = nSamples;
int outCount = (int) (inCount * resampleRatio);
short int * resampledBuffer = new short int[(outCount+1)* channels];
int converted;
#ifdef HAVE_SRC_LIB
converterData.input_frames = nSamples;
src_short_to_float_array (shortBuffer, converterData.data_in, totalSamples);
int srcError = src_process (converter, &converterData);
if (srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
converted = converterData.output_frames_gen;
src_float_to_short_array(converterData.data_out, resampledBuffer, converted*channels);
#else
converted = converter->resample( inCount,
outCount,
shortBuffer,
resampledBuffer );
#endif
vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState,
converted);
Util::conv( resampledBuffer,
converted * channels,
vorbisBuffer,
channels);
delete[] resampledBuffer;
vorbis_analysis_wrote( &vorbisDspState, converted);
} else {
vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState, nSamples);
Util::conv( shortBuffer, totalSamples, vorbisBuffer, channels);
vorbis_analysis_wrote( &vorbisDspState, nSamples);
}
delete[] shortBuffer;
vorbisBlocksOut();
return processed;
}
/*------------------------------------------------------------------------------
* Flush the data from the encoder
*----------------------------------------------------------------------------*/
void
VorbisLibEncoder :: flush ( void )
throw ( Exception )
{
if ( !isOpen() ) {
return;
}
vorbis_analysis_wrote( &vorbisDspState, 0);
vorbisBlocksOut();
getSink()->flush();
}
/*------------------------------------------------------------------------------
* Send pending Vorbis blocks to the underlying stream
*----------------------------------------------------------------------------*/
void
VorbisLibEncoder :: vorbisBlocksOut ( void ) throw ( Exception )
{
while ( 1 == vorbis_analysis_blockout( &vorbisDspState, &vorbisBlock) ) {
ogg_packet oggPacket;
ogg_page oggPage;
vorbis_analysis( &vorbisBlock, &oggPacket);
vorbis_bitrate_addblock( &vorbisBlock);
while ( vorbis_bitrate_flushpacket( &vorbisDspState, &oggPacket) ) {
ogg_stream_packetin( &oggStreamState, &oggPacket);
while ( ogg_stream_pageout( &oggStreamState, &oggPage) ) {
int written = 0;
written = getSink()->write(oggPage.header, oggPage.header_len);
written += getSink()->write( oggPage.body, oggPage.body_len);
if ( written < oggPage.header_len + oggPage.body_len ) {
// just let go data that could not be written
reportEvent( 2,
"couldn't write full vorbis data to underlying sink",
oggPage.header_len + oggPage.body_len - written);
}
}
}
}
}
/*------------------------------------------------------------------------------
* Close the encoding session
*----------------------------------------------------------------------------*/
void
VorbisLibEncoder :: close ( void ) throw ( Exception )
{
if ( isOpen() ) {
flush();
ogg_stream_clear( &oggStreamState);
vorbis_block_clear( &vorbisBlock);
vorbis_dsp_clear( &vorbisDspState);
vorbis_comment_clear( &vorbisComment);
vorbis_info_clear( &vorbisInfo);
encoderOpen = false;
getSink()->close();
}
}
#endif // HAVE_VORBIS_LIB

View File

@ -0,0 +1,453 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : VorbisLibEncoder.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef VORBIS_LIB_ENCODER_H
#define VORBIS_LIB_ENCODER_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_VORBIS_LIB
#include <vorbis/vorbisenc.h>
#else
#error configure for Ogg Vorbis
#endif
#include "Ref.h"
#include "Exception.h"
#include "Reporter.h"
#include "AudioEncoder.h"
#include "Sink.h"
#ifdef HAVE_SRC_LIB
#include <samplerate.h>
#else
#include "aflibConverter.h"
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A class representing the ogg vorbis encoder linked as a shared object or
* as a static library.
*
* @author $Author$
* @version $Revision$
*/
class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
{
private:
/**
* Value indicating if the encoding process is going on
*/
bool encoderOpen;
/**
* Ogg Vorbis library global info
*/
vorbis_info vorbisInfo;
/**
* Ogg Vorbis library global DSP state
*/
vorbis_dsp_state vorbisDspState;
/**
* Ogg Vorbis library global block
*/
vorbis_block vorbisBlock;
/**
* Ogg Vorbis library global comment
*/
vorbis_comment vorbisComment;
/**
* Ogg library global stream state
*/
ogg_stream_state oggStreamState;
/**
* Maximum bitrate of the output in kbits/sec. If 0, don't care.
*/
unsigned int outMaxBitrate;
/**
* Resample ratio
*/
double resampleRatio;
/**
* sample rate converter object for possible resampling
*/
#ifdef HAVE_SRC_LIB
SRC_STATE * converter;
SRC_DATA converterData;
#else
aflibConverter * converter;
#endif
/**
* Initialize the object.
*
* @param the maximum bit rate
* @exception Exception
*/
void
init ( unsigned int outMaxBitrate ) throw ( Exception );
/**
* De-initialize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
if ( converter ) {
#ifdef HAVE_SRC_LIB
delete [] converterData.data_in;
delete [] converterData.data_out;
src_delete (converter);
#else
delete converter;
#endif
}
}
/**
* Send pending Vorbis blocks to the underlying stream
*/
void
vorbisBlocksOut( void ) throw ( Exception );
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
VorbisLibEncoder ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor.
*
* @param sink the sink to send encoded output to
* @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input.
* @param inBigEndian shows if the input is big or little endian
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, inSampleRate is used.
* @param outMaxBitrate maximum output bitrate.
* 0 if not used.
* @param outChannel number of channels of the output.
* If 0, inChannel is used.
* @exception Exception
*/
inline
VorbisLibEncoder ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample,
unsigned int inChannel,
bool inBigEndian,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
unsigned int outMaxBitrate = 0 )
throw ( Exception )
: AudioEncoder ( sink,
inSampleRate,
inBitsPerSample,
inChannel,
inBigEndian,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( outMaxBitrate);
}
/**
* Constructor.
*
* @param sink the sink to send encoded output to
* @param as get input sample rate, bits per sample and channels
* from this AudioSource.
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, input sample rate is used.
* @param outMaxBitrate maximum output bitrate.
* 0 if not used.
* @param outChannel number of channels of the output.
* If 0, input channel is used.
* @exception Exception
*/
inline
VorbisLibEncoder ( Sink * sink,
const AudioSource * as,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
unsigned int outMaxBitrate = 0 )
throw ( Exception )
: AudioEncoder ( sink,
as,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( outMaxBitrate);
}
/**
* Copy constructor.
*
* @param encoder the VorbisLibEncoder to copy.
*/
inline
VorbisLibEncoder ( const VorbisLibEncoder & encoder )
throw ( Exception )
: AudioEncoder( encoder )
{
if( encoder.isOpen() ) {
throw Exception(__FILE__, __LINE__, "don't copy open encoders");
}
init( encoder.getOutMaxBitrate() );
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~VorbisLibEncoder ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
strip();
}
/**
* Assignment operator.
*
* @param encoder the VorbisLibEncoder to assign this to.
* @return a reference to this VorbisLibEncoder.
* @exception Exception
*/
inline virtual VorbisLibEncoder &
operator= ( const VorbisLibEncoder & encoder ) throw ( Exception )
{
if( encoder.isOpen() ) {
throw Exception(__FILE__, __LINE__, "don't copy open encoders");
}
if ( this != &encoder ) {
strip();
AudioEncoder::operator=( encoder);
init( encoder.getOutMaxBitrate() );
}
return *this;
}
/**
* Get the maximum bit rate of the output in kbits/sec,
* for fixed / average bitrate encodings.
*
* @return the maximum bit rate of the output, or 0 if not set.
*/
inline unsigned int
getOutMaxBitrate ( void ) const throw ()
{
return outMaxBitrate;
}
/**
* Check whether encoding is in progress.
*
* @return true if encoding is in progress, false otherwise.
*/
inline virtual bool
isRunning ( void ) const throw ()
{
return isOpen();
}
/**
* Start encoding. This function returns as soon as possible,
* with encoding started in the background.
*
* @return true if encoding has started, false otherwise.
* @exception Exception
*/
inline virtual bool
start ( void ) throw ( Exception )
{
return open();
}
/**
* Stop encoding. Stops the encoding running in the background.
*
* @exception Exception
*/
inline virtual void
stop ( void ) throw ( Exception )
{
return close();
}
/**
* Open an encoding session.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the encoding session is open.
*
* @return true if the encoding session is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return encoderOpen;
}
/**
* Check if the encoder is ready to accept data.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the encoder is ready to accept data,
* false otherwise.
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
if ( !isOpen() ) {
return false;
}
if ( 1 == vorbis_analysis_blockout( &vorbisDspState, &vorbisBlock) ) {
return getSink()->canWrite(sec, usec);
} else {
return true;
}
}
/**
* Write data to the encoder.
* Buf is expected to be a sequence of big-endian 16 bit values,
* with left and right channels interleaved. Len is the number of
* bytes, must be a multiple of 4.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* Flush all data that was written to the encoder to the underlying
* connection.
*
* @exception Exception
*/
virtual void
flush ( void ) throw ( Exception );
/**
* Close the encoding session.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* VORBIS_LIB_ENCODER_H */

View File

@ -0,0 +1,278 @@
/*------------------------------------------------------------------------------
Copyright (c) 2005 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : aacPlusEncoder.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// compile the whole file only if aacplus support configured in
#ifdef HAVE_AACPLUS_LIB
#include "Exception.h"
#include "Util.h"
#include "aacPlusEncoder.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Open an encoding session
*----------------------------------------------------------------------------*/
bool
aacPlusEncoder :: open ( void )
throw ( Exception )
{
if ( isOpen() ) {
close();
}
// open the underlying sink
if ( !sink->open() ) {
throw Exception( __FILE__, __LINE__,
"aacplus lib opening underlying sink error");
}
reportEvent(1, "Using aacplus codec");
encoderHandle = aacplusEncOpen(getOutSampleRate(),
getInChannel(),
&inputSamples,
&maxOutputBytes);
aacplusEncConfiguration * aacplusConfig;
aacplusConfig = aacplusEncGetCurrentConfiguration(encoderHandle);
aacplusConfig->bitRate = getOutBitrate() * 1000;
aacplusConfig->bandWidth = lowpass;
aacplusConfig->outputFormat = 1;
aacplusConfig->inputFormat = AACPLUS_INPUT_16BIT;
aacplusConfig->nChannelsOut = getOutChannel();
if (!aacplusEncSetConfiguration(encoderHandle, aacplusConfig)) {
throw Exception(__FILE__, __LINE__,
"error configuring libaacplus library");
}
// initialize the resampling coverter if needed
if ( converter ) {
#ifdef HAVE_SRC_LIB
converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel());
converterData.data_in = new float[converterData.input_frames*getInChannel()];
converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1);
if ((int) inputSamples > getInChannel() * converterData.output_frames) {
resampledOffset = new float[2 * inputSamples];
} else {
resampledOffset = new float[2 * getInChannel() * converterData.input_frames];
}
converterData.src_ratio = resampleRatio;
converterData.end_of_input = 0;
#else
converter->initialize( resampleRatio, getInChannel());
//needed 2x(converted input samples) to handle offsets
int outCount = 2 * getInChannel() * (inputSamples + 1);
if (resampleRatio > 1)
outCount = (int) (outCount * resampleRatio);
resampledOffset = new short int[outCount];
#endif
resampledOffsetSize = 0;
}
aacplusOpen = true;
reportEvent(10, "nChannelsAAC", aacplusConfig->nChannelsOut);
reportEvent(10, "sampleRateAAC", aacplusConfig->sampleRate);
reportEvent(10, "inSamples", inputSamples);
return true;
}
/*------------------------------------------------------------------------------
* Write data to the encoder
*----------------------------------------------------------------------------*/
unsigned int
aacPlusEncoder :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
if ( !isOpen() || len == 0) {
return 0;
}
unsigned int channels = getInChannel();
unsigned int bitsPerSample = getInBitsPerSample();
unsigned int sampleSize = (bitsPerSample / 8) * channels;
unsigned char * b = (unsigned char*) buf;
unsigned int processed = len - (len % sampleSize);
unsigned int nSamples = processed / sampleSize;
unsigned char * aacplusBuf = new unsigned char[maxOutputBytes];
int samples = (int) nSamples * channels;
int processedSamples = 0;
if ( converter ) {
unsigned int converted;
#ifdef HAVE_SRC_LIB
src_short_to_float_array ((short *) b, converterData.data_in, samples);
converterData.input_frames = nSamples;
converterData.data_out = resampledOffset + (resampledOffsetSize * channels);
int srcError = src_process (converter, &converterData);
if (srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
converted = converterData.output_frames_gen;
#else
int inCount = nSamples;
short int * shortBuffer = new short int[samples];
int outCount = (int) (inCount * resampleRatio);
Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian());
converted = converter->resample( inCount,
outCount+1,
shortBuffer,
&resampledOffset[resampledOffsetSize*channels]);
delete[] shortBuffer;
#endif
resampledOffsetSize += converted;
// encode samples (if enough)
while(resampledOffsetSize - processedSamples >= inputSamples/channels) {
#ifdef HAVE_SRC_LIB
short *shortData = new short[inputSamples];
src_float_to_short_array(resampledOffset + (processedSamples * channels),
shortData, inputSamples) ;
int outputBytes = aacplusEncEncode(encoderHandle,
(int32_t*) shortData,
inputSamples,
aacplusBuf,
maxOutputBytes);
delete [] shortData;
#else
int outputBytes = aacplusEncEncode(encoderHandle,
(int32_t*) &resampledOffset[processedSamples*channels],
inputSamples,
aacplusBuf,
maxOutputBytes);
#endif
unsigned int wrote = getSink()->write(aacplusBuf, outputBytes);
if (wrote < outputBytes) {
reportEvent(3, "aacPlusEncoder :: write, couldn't write full data to underlying sink");
}
processedSamples+=inputSamples/channels;
}
if (processedSamples && (int) resampledOffsetSize >= processedSamples) {
resampledOffsetSize -= processedSamples;
//move least part of resampled data to beginning
if(resampledOffsetSize)
#ifdef HAVE_SRC_LIB
resampledOffset = (float *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*channels*sizeof(float));
#else
resampledOffset = (short *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*sampleSize);
#endif
}
} else {
while (processedSamples < samples) {
int inSamples = samples - processedSamples < (int) inputSamples
? samples - processedSamples
: inputSamples;
int outputBytes = aacplusEncEncode(encoderHandle,
(int32_t*) (b + processedSamples/sampleSize),
inSamples,
aacplusBuf,
maxOutputBytes);
unsigned int wrote = getSink()->write(aacplusBuf, outputBytes);
if (wrote < outputBytes) {
reportEvent(3, "aacPlusEncoder :: write, couldn't write full data to underlying sink");
}
processedSamples += inSamples;
}
}
delete[] aacplusBuf;
// return processedSamples;
return samples * sampleSize;
}
/*------------------------------------------------------------------------------
* Flush the data from the encoder
*----------------------------------------------------------------------------*/
void
aacPlusEncoder :: flush ( void )
throw ( Exception )
{
if ( !isOpen() ) {
return;
}
sink->flush();
}
/*------------------------------------------------------------------------------
* Close the encoding session
*----------------------------------------------------------------------------*/
void
aacPlusEncoder :: close ( void ) throw ( Exception )
{
if ( isOpen() ) {
flush();
aacplusEncClose(encoderHandle);
aacplusOpen = false;
sink->close();
}
}
#endif // HAVE_AACPLUS_LIB

View File

@ -0,0 +1,520 @@
/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : aacPlusEncoder.h
Version : $Revision$
Author : $Author$
Location : $HeadURL$
Copyright notice:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef AACP_ENCODER_H
#define AACP_ENCODER_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_AACPLUS_LIB
#include <aacplus.h>
#else
#error configure with aacplus
#endif
#include <cassert>
#include <cstring>
#include "Ref.h"
#include "Exception.h"
#include "Reporter.h"
#include "AudioEncoder.h"
#include "Sink.h"
#ifdef HAVE_SRC_LIB
#include <samplerate.h>
#else
#include "aflibConverter.h"
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* A class representing aacplus AAC+ encoder.
*
* @author $Author$
* @version $Revision$
*/
class aacPlusEncoder : public AudioEncoder, public virtual Reporter
{
private:
/**
* A flag to indicate if the encoding session is open.
*/
bool aacplusOpen;
/**
* Resample ratio
*/
double resampleRatio;
/**
* sample rate converter object for possible resampling
*/
#ifdef HAVE_SRC_LIB
SRC_STATE *converter;
SRC_DATA converterData;
float *resampledOffset;
#else
aflibConverter *converter;
short *resampledOffset;
#endif
unsigned int resampledOffsetSize;
/**
* The Sink to dump aac+ data to
*/
Ref<Sink> sink;
/**
* The handle to the AAC+ encoder instance.
*/
aacplusEncHandle encoderHandle;
/**
* The maximum number of input samples to supply to the encoder.
*/
unsigned long inputSamples;
/**
* The maximum number of output bytes the encoder returns in one call.
*/
unsigned long maxOutputBytes;
/**
* Lowpass filter. Sound frequency in Hz, from where up the
* input is cut.
*/
int lowpass;
/**
* Initialize the object.
*
* @param sink the sink to send mp3 output to
* @exception Exception
*/
inline void
init ( Sink * sink, int lowpass) throw (Exception)
{
this->aacplusOpen = false;
this->sink = sink;
this->lowpass = lowpass;
/* TODO: if we have float as input, we don't need conversion */
if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 32 ) {
throw Exception( __FILE__, __LINE__,
"specified bits per sample not supported",
getInBitsPerSample() );
}
if ( getInChannel() > 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of input channels for the encoder",
getInChannel() );
}
if ( getOutChannel() > 2 ) {
throw Exception( __FILE__, __LINE__,
"unsupported number of output channels for the encoder",
getOutChannel() );
}
if ( getOutSampleRate() == getInSampleRate() ) {
resampleRatio = 1;
converter = 0;
} else if (getInBitsPerSample() == 16) {
resampleRatio = ( (double) getOutSampleRate() /
(double) getInSampleRate() );
// Determine if we can use linear interpolation.
// The inverse of the ratio must be a power of two for linear mode to
// be of sufficient quality.
bool useLinear = true;
double inverse = 1 / resampleRatio;
int integer = (int) inverse;
// Check that the inverse of the ratio is an integer
if( integer == inverse ) {
while( useLinear && integer ) { // Loop through the bits
// If the lowest order bit is not the only one set
if( integer & 1 && integer != 1 ) {
// Not a power of two; cannot use linear
useLinear = false;
} else {
// Shift all the bits over and try again
integer >>= 1;
}
}
} else {
useLinear = false;
}
// If we get here and useLinear is still true, then we have
// a power of two.
// open the aflibConverter in
// - high quality
// - linear or quadratic (non-linear) based on algorithm
// - not filter interpolation
#ifdef HAVE_SRC_LIB
int srcError = 0;
converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST,
getInChannel(), &srcError);
if(srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
#else
converter = new aflibConverter( true, useLinear, false);
#endif
} else {
throw Exception( __FILE__, __LINE__,
"specified bits per sample with samplerate conversion not supported",
getInBitsPerSample() );
}
}
/**
* De-initialize the object.
*
* @exception Exception
*/
inline void
strip ( void ) throw ( Exception )
{
if ( converter ) {
#ifdef HAVE_SRC_LIB
delete [] converterData.data_in;
src_delete (converter);
#else
delete converter;
#endif
delete [] resampledOffset;
}
}
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
aacPlusEncoder ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
public:
/**
* Constructor.
*
* @param sink the sink to send mp3 output to
* @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input.
* @param inBigEndian shows if the input is big or little endian
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, inSampleRate is used.
* @param outChannel number of channels of the output.
* If 0, inChannel is used.
* @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut.
* If 0, aacplus's default values are used,
* which depends on the out sample rate.
* @exception Exception
*/
inline
aacPlusEncoder ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample,
unsigned int inChannel,
bool inBigEndian,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
int lowpass = 0)
throw ( Exception )
: AudioEncoder ( sink,
inSampleRate,
inBitsPerSample,
inChannel,
inBigEndian,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( sink, lowpass);
}
/**
* Constructor.
*
* @param sink the sink to send mp3 output to
* @param as get input sample rate, bits per sample and channels
* from this AudioSource.
* @param outBitrateMode the bit rate mode of the output.
* @param outBitrate bit rate of the output (kbits/sec).
* @param outQuality the quality of the stream.
* @param outSampleRate sample rate of the output.
* If 0, input sample rate is used.
* @param outChannel number of channels of the output.
* If 0, input channel is used.
* @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut.
* If 0, aacplus's default values are used,
* which depends on the out sample rate.
* @exception Exception
*/
inline
aacPlusEncoder ( Sink * sink,
const AudioSource * as,
BitrateMode outBitrateMode,
unsigned int outBitrate,
double outQuality,
unsigned int outSampleRate = 0,
unsigned int outChannel = 0,
int lowpass = 0)
throw ( Exception )
: AudioEncoder ( sink,
as,
outBitrateMode,
outBitrate,
outQuality,
outSampleRate,
outChannel )
{
init( sink, lowpass );
}
/**
* Copy constructor.
*
* @param encoder the aacPlusEncoder to copy.
*/
inline
aacPlusEncoder ( const aacPlusEncoder & encoder )
throw ( Exception )
: AudioEncoder( encoder )
{
init( encoder.sink.get(), encoder.lowpass);
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~aacPlusEncoder ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
strip();
}
/**
* Assignment operator.
*
* @param encoder the aacPlusEncoder to assign this to.
* @return a reference to this aacPlusEncoder.
* @exception Exception
*/
inline virtual aacPlusEncoder &
operator= ( const aacPlusEncoder & encoder ) throw ( Exception )
{
if ( this != &encoder ) {
strip();
AudioEncoder::operator=( encoder);
init( encoder.sink.get(), encoder.lowpass);
}
return *this;
}
/**
* Get the version string of the underlying aacplus library.
*
* @return the version string of the underlying aacplus library.
*/
inline const char *
getAacPlusVersion( void )
{
char * id;
//char * copyright;
/* aacplusEncGetVersion(&id, &copyright); */
return id;
}
/**
* Check whether encoding is in progress.
*
* @return true if encoding is in progress, false otherwise.
*/
inline virtual bool
isRunning ( void ) const throw ()
{
return isOpen();
}
/**
* Start encoding. This function returns as soon as possible,
* with encoding started in the background.
*
* @return true if encoding has started, false otherwise.
* @exception Exception
*/
inline virtual bool
start ( void ) throw ( Exception )
{
return open();
}
/**
* Stop encoding. Stops the encoding running in the background.
*
* @exception Exception
*/
inline virtual void
stop ( void ) throw ( Exception )
{
return close();
}
/**
* Open an encoding session.
*
* @return true if opening was successfull, false otherwise.
* @exception Exception
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the encoding session is open.
*
* @return true if the encoding session is open, false otherwise.
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return aacplusOpen;
}
/**
* Check if the encoder is ready to accept data.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the encoder is ready to accept data,
* false otherwise.
* @exception Exception
*/
inline virtual bool
canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
if ( !isOpen() ) {
return false;
}
return true;
}
/**
* Write data to the encoder.
* Buf is expected to be a sequence of big-endian 16 bit values,
* with left and right channels interleaved. Len is the number of
* bytes, must be a multiple of 4.
*
* @param buf the data to write.
* @param len number of bytes to write from buf.
* @return the number of bytes written (may be less than len).
* @exception Exception
*/
virtual unsigned int
write ( const void * buf,
unsigned int len ) throw ( Exception );
/**
* Flush all data that was written to the encoder to the underlying
* connection.
*
* @exception Exception
*/
virtual void
flush ( void ) throw ( Exception );
/**
* Close the encoding session.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* AACP_ENCODER_H */

View File

@ -0,0 +1,797 @@
/*
* Copyright: (C) 2000 Julius O. Smith
*
* 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Julius O. Smith jos@ccrma.stanford.edu
*
*/
/* This code was modified by Bruce Forsberg (forsberg@tns.net) to make it
into a C++ class
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "aflibConverter.h"
#include "aflibConverterLargeFilter.h"
#include "aflibConverterSmallFilter.h"
#include "aflibDebug.h"
#if (!defined(TRUE) || !defined(FALSE))
# define TRUE 1
# define FALSE 0
#endif
/*
* The configuration constants below govern
* the number of bits in the input sample and filter coefficients, the
* number of bits to the right of the binary-point for fixed-point math, etc.
*/
/* Conversion constants */
#define Nhc 8
#define Na 7
#define Np (Nhc+Na)
#define Npc (1<<Nhc)
#define Amask ((1<<Na)-1)
#define Pmask ((1<<Np)-1)
#define Nh 16
#define Nb 16
#define Nhxn 14
#define Nhg (Nh-Nhxn)
#define NLpScl 13
/* Description of constants:
*
* Npc - is the number of look-up values available for the lowpass filter
* between the beginning of its impulse response and the "cutoff time"
* of the filter. The cutoff time is defined as the reciprocal of the
* lowpass-filter cut off frequence in Hz. For example, if the
* lowpass filter were a sinc function, Npc would be the index of the
* impulse-response lookup-table corresponding to the first zero-
* crossing of the sinc function. (The inverse first zero-crossing
* time of a sinc function equals its nominal cutoff frequency in Hz.)
* Npc must be a power of 2 due to the details of the current
* implementation. The default value of 512 is sufficiently high that
* using linear interpolation to fill in between the table entries
* gives approximately 16-bit accuracy in filter coefficients.
*
* Nhc - is log base 2 of Npc.
*
* Na - is the number of bits devoted to linear interpolation of the
* filter coefficients.
*
* Np - is Na + Nhc, the number of bits to the right of the binary point
* in the integer "time" variable. To the left of the point, it indexes
* the input array (X), and to the right, it is interpreted as a number
* between 0 and 1 sample of the input X. Np must be less than 16 in
* this implementation.
*
* Nh - is the number of bits in the filter coefficients. The sum of Nh and
* the number of bits in the input data (typically 16) cannot exceed 32.
* Thus Nh should be 16. The largest filter coefficient should nearly
* fill 16 bits (32767).
*
* Nb - is the number of bits in the input data. The sum of Nb and Nh cannot
* exceed 32.
*
* Nhxn - is the number of bits to right shift after multiplying each input
* sample times a filter coefficient. It can be as great as Nh and as
* small as 0. Nhxn = Nh-2 gives 2 guard bits in the multiply-add
* accumulation. If Nhxn=0, the accumulation will soon overflow 32 bits.
*
* Nhg - is the number of guard bits in mpy-add accumulation (equal to Nh-Nhxn)
*
* NLpScl - is the number of bits allocated to the unity-gain normalization
* factor. The output of the lowpass filter is multiplied by LpScl and
* then right-shifted NLpScl bits. To avoid overflow, we must have
* Nb+Nhg+NLpScl < 32.
*/
aflibConverter::aflibConverter(
bool high_quality,
bool linear_interpolation,
bool filter_interpolation)
{
/* TODO put all these into an enum as it only makes sense to have
* one true at a time. - DAS
*/
interpFilt = filter_interpolation;
largeFilter = high_quality;
linearInterp = linear_interpolation;
_II = NULL;
_JJ = NULL;
_vol = 1.0;
}
aflibConverter::~aflibConverter()
{
deleteMemory();
}
void
aflibConverter::deleteMemory()
{
int i;
// Delete memory for the input and output arrays
if (_II != NULL)
{
for (i = 0; i < _nChans; i++)
{
delete [] _II[i];
_II[i] = NULL;
delete [] _JJ[i];
_JJ[i] = NULL;
}
delete [] _II;
_II = NULL;
delete [] _JJ;
_JJ = NULL;
}
}
void
aflibConverter::initialize(
double fac,
int channels,
double volume)
{
// This function will allow one to stream data. When a new data stream is to
// be input then this function should be called. Even if the factor and number
// of channels don't change. Otherwise each new data block sent to resample
// will be considered part of the previous data block. This function also allows
// one to specified a multiplication factor to adjust the final output. This
// applies to the small and large filter.
int i;
// Delete all previous allocated input and output buffer memory
deleteMemory();
_factor = fac;
_nChans = channels;
_initial = TRUE;
_vol = volume;
// Allocate all new memory
_II = new short * [_nChans];
_JJ = new short * [_nChans];
for (i = 0; i < _nChans; i++)
{
// Add extra to allow of offset of input data (Xoff in main routine)
_II[i] = new short[IBUFFSIZE + 256];
_JJ[i] = new short[(int)(((double)IBUFFSIZE)*_factor)];
memset(_II[i], 0, sizeof(short) * (IBUFFSIZE + 256));
}
}
int
aflibConverter::resample( /* number of output samples returned */
int& inCount, /* number of input samples to convert */
int outCount, /* number of output samples to compute */
short inArray[], /* input data */
short outArray[]) /* output data */
{
int Ycount;
// Use fast method with no filtering. Poor quality
if (linearInterp == TRUE)
Ycount = resampleFast(inCount,outCount,inArray,outArray);
// Use small filtering. Good qulaity
else if (largeFilter == FALSE)
Ycount = resampleWithFilter(inCount,outCount,inArray,outArray,
SMALL_FILTER_IMP, SMALL_FILTER_IMPD,
(unsigned short)(SMALL_FILTER_SCALE * _vol),
SMALL_FILTER_NMULT, SMALL_FILTER_NWING);
// Use large filtering Great quality
else
Ycount = resampleWithFilter(inCount,outCount,inArray,outArray,
LARGE_FILTER_IMP, LARGE_FILTER_IMPD,
(unsigned short)(LARGE_FILTER_SCALE * _vol),
LARGE_FILTER_NMULT, LARGE_FILTER_NWING);
_initial = FALSE;
return (Ycount);
}
int
aflibConverter::err_ret(const char *s)
{
aflib_debug("resample: %s \n\n",s); /* Display error message */
return -1;
}
int
aflibConverter::readData(
int inCount, /* _total_ number of frames in input file */
short inArray[], /* input data */
short *outPtr[], /* array receiving chan samps */
int dataArraySize, /* size of these arrays */
int Xoff, /* read into input array starting at this index */
bool init_count)
{
int i, Nsamps, c;
static unsigned int framecount; /* frames previously read */
short *ptr;
if (init_count == TRUE)
framecount = 0; /* init this too */
Nsamps = dataArraySize - Xoff; /* Calculate number of samples to get */
// Don't overrun input buffers
if (Nsamps > (inCount - (int)framecount))
{
Nsamps = inCount - framecount;
}
for (c = 0; c < _nChans; c++)
{
ptr = outPtr[c];
ptr += Xoff; /* Start at designated sample number */
for (i = 0; i < Nsamps; i++)
*ptr++ = (short) inArray[c * inCount + i + framecount];
}
framecount += Nsamps;
if ((int)framecount >= inCount) /* return index of last samp */
return (((Nsamps - (framecount - inCount)) - 1) + Xoff);
else
return 0;
}
int
aflibConverter::SrcLinear(
short X[],
short Y[],
double factor,
unsigned int *Time,
unsigned short& Nx,
unsigned short Nout)
{
short iconst;
short *Xp, *Ystart;
int v,x1,x2;
double dt; /* Step through input signal */
unsigned int dtb; /* Fixed-point version of Dt */
// unsigned int endTime; /* When Time reaches EndTime, return to user */
unsigned int start_sample, end_sample;
dt = 1.0/factor; /* Output sampling period */
dtb = (unsigned int)(dt*(1<<Np) + 0.5); /* Fixed-point representation */
start_sample = (*Time)>>Np;
Ystart = Y;
// endTime = *Time + (1<<Np)*(int)Nx;
/*
* TODO
* DAS: not sure why this was changed from *Time < endTime
* update: *Time < endTime causes seg fault. Also adds a clicking sound.
*/
while (Y - Ystart != Nout)
// while (*Time < endTime)
{
iconst = (*Time) & Pmask;
Xp = &X[(*Time)>>Np]; /* Ptr to current input sample */
x1 = *Xp++;
x2 = *Xp;
x1 *= ((1<<Np)-iconst);
x2 *= iconst;
v = x1 + x2;
*Y++ = WordToHword(v,Np); /* Deposit output */
*Time += dtb; /* Move to next sample by time increment */
}
end_sample = (*Time)>>Np;
Nx = end_sample - start_sample;
return (Y - Ystart); /* Return number of output samples */
}
int
aflibConverter::SrcUp(
short X[],
short Y[],
double factor,
unsigned int *Time,
unsigned short& Nx,
unsigned short Nout,
unsigned short Nwing,
unsigned short LpScl,
short Imp[],
short ImpD[],
bool Interp)
{
short *Xp, *Ystart;
int v;
double dt; /* Step through input signal */
unsigned int dtb; /* Fixed-point version of Dt */
// unsigned int endTime; /* When Time reaches EndTime, return to user */
unsigned int start_sample, end_sample;
dt = 1.0/factor; /* Output sampling period */
dtb = (unsigned int)(dt*(1<<Np) + 0.5); /* Fixed-point representation */
start_sample = (*Time)>>Np;
Ystart = Y;
// endTime = *Time + (1<<Np)*(int)Nx;
/*
* TODO
* DAS: not sure why this was changed from *Time < endTime
* update: *Time < endTime causes seg fault. Also adds a clicking sound.
*/
while (Y - Ystart != Nout)
// while (*Time < endTime)
{
Xp = &X[*Time>>Np]; /* Ptr to current input sample */
/* Perform left-wing inner product */
v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, (short)(*Time&Pmask),-1);
/* Perform right-wing inner product */
v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1,
(short)((((*Time)^Pmask)+1)&Pmask), 1);
v >>= Nhg; /* Make guard bits */
v *= LpScl; /* Normalize for unity filter gain */
*Y++ = WordToHword(v,NLpScl); /* strip guard bits, deposit output */
*Time += dtb; /* Move to next sample by time increment */
}
end_sample = (*Time)>>Np;
Nx = end_sample - start_sample;
return (Y - Ystart); /* Return the number of output samples */
}
int
aflibConverter::SrcUD(
short X[],
short Y[],
double factor,
unsigned int *Time,
unsigned short& Nx,
unsigned short Nout,
unsigned short Nwing,
unsigned short LpScl,
short Imp[],
short ImpD[],
bool Interp)
{
short *Xp, *Ystart;
int v;
double dh; /* Step through filter impulse response */
double dt; /* Step through input signal */
// unsigned int endTime; /* When Time reaches EndTime, return to user */
unsigned int dhb, dtb; /* Fixed-point versions of Dh,Dt */
unsigned int start_sample, end_sample;
dt = 1.0/factor; /* Output sampling period */
dtb = (unsigned int)(dt*(1<<Np) + 0.5); /* Fixed-point representation */
dh = MIN(Npc, factor*Npc); /* Filter sampling period */
dhb = (unsigned int)(dh*(1<<Na) + 0.5); /* Fixed-point representation */
start_sample = (*Time)>>Np;
Ystart = Y;
// endTime = *Time + (1<<Np)*(int)Nx;
/*
* TODO
* DAS: not sure why this was changed from *Time < endTime
* update: *Time < endTime causes seg fault. Also adds a clicking sound.
*/
while (Y - Ystart != Nout)
// while (*Time < endTime)
{
Xp = &X[*Time>>Np]; /* Ptr to current input sample */
v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, (short)(*Time&Pmask),
-1, dhb); /* Perform left-wing inner product */
v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1,
(short)((((*Time)^Pmask)+1)&Pmask), 1, dhb); /* Perform right-wing inner product */
v >>= Nhg; /* Make guard bits */
v *= LpScl; /* Normalize for unity filter gain */
*Y++ = WordToHword(v,NLpScl); /* strip guard bits, deposit output */
*Time += dtb; /* Move to next sample by time increment */
}
end_sample = (*Time)>>Np;
Nx = end_sample - start_sample;
return (Y - Ystart); /* Return the number of output samples */
}
int
aflibConverter::resampleFast( /* number of output samples returned */
int& inCount, /* number of input samples to convert */
int outCount, /* number of output samples to compute */
short inArray[], /* input data */
short outArray[]) /* output data */
{
unsigned int Time2; /* Current time/pos in input sample */
#if 0
unsigned short Ncreep;
#endif
unsigned short Xp, Xoff, Xread;
int OBUFFSIZE = (int)(((double)IBUFFSIZE)*_factor);
unsigned short Nout = 0, Nx, orig_Nx;
unsigned short maxOutput;
int total_inCount = 0;
int c, i, Ycount, last;
bool first_pass = TRUE;
Xoff = 10;
Nx = IBUFFSIZE - 2*Xoff; /* # of samples to process each iteration */
last = 0; /* Have not read last input sample yet */
Ycount = 0; /* Current sample and length of output file */
Xp = Xoff; /* Current "now"-sample pointer for input */
Xread = Xoff; /* Position in input array to read into */
if (_initial == TRUE)
_Time = (Xoff<<Np); /* Current-time pointer for converter */
do {
if (!last) /* If haven't read last sample yet */
{
last = readData(inCount, inArray, _II,
IBUFFSIZE, (int)Xread,first_pass);
first_pass = FALSE;
if (last && (last-Xoff<Nx)) { /* If last sample has been read... */
Nx = last-Xoff; /* ...calc last sample affected by filter */
if (Nx <= 0)
break;
}
}
if ((outCount-Ycount) > (OBUFFSIZE - (2*Xoff*_factor)) )
maxOutput = OBUFFSIZE - (unsigned short)(2*Xoff*_factor);
else
maxOutput = outCount-Ycount;
for (c = 0; c < _nChans; c++)
{
orig_Nx = Nx;
Time2 = _Time;
/* Resample stuff in input buffer */
Nout=SrcLinear(_II[c],_JJ[c],_factor,&Time2,orig_Nx,maxOutput);
}
Nx = orig_Nx;
_Time = Time2;
_Time -= (Nx<<Np); /* Move converter Nx samples back in time */
Xp += Nx; /* Advance by number of samples processed */
#if 0
Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */
if (Ncreep) {
Time -= (Ncreep<<Np); /* Remove time accumulation */
Xp += Ncreep; /* and add it to read pointer */
}
#endif
for (c = 0; c < _nChans; c++)
{
for (i=0; i<IBUFFSIZE-Xp+Xoff; i++) { /* Copy part of input signal */
_II[c][i] = _II[c][i+Xp-Xoff]; /* that must be re-used */
}
}
if (last) { /* If near end of sample... */
last -= Xp; /* ...keep track were it ends */
if (!last) /* Lengthen input by 1 sample if... */
last++; /* ...needed to keep flag TRUE */
}
Xread = IBUFFSIZE - Nx; /* Pos in input buff to read new data into */
Xp = Xoff;
Ycount += Nout;
if (Ycount>outCount) {
Nout -= (Ycount-outCount);
Ycount = outCount;
}
if (Nout > OBUFFSIZE) /* Check to see if output buff overflowed */
return err_ret("Output array overflow");
for (c = 0; c < _nChans; c++)
for (i = 0; i < Nout; i++)
outArray[c * outCount + i + Ycount - Nout] = _JJ[c][i];
total_inCount += Nx;
} while (Ycount < outCount); /* Continue until done */
inCount = total_inCount;
return(Ycount); /* Return # of samples in output file */
}
int
aflibConverter::resampleWithFilter( /* number of output samples returned */
int& inCount, /* number of input samples to convert */
int outCount, /* number of output samples to compute */
short inArray[], /* input data */
short outArray[], /* output data */
short Imp[], short ImpD[],
unsigned short LpScl, unsigned short Nmult, unsigned short Nwing)
{
unsigned int Time2; /* Current time/pos in input sample */
#if 0
unsigned short Ncreep;
#endif
unsigned short Xp, Xoff, Xread;
int OBUFFSIZE = (int)(((double)IBUFFSIZE)*_factor);
unsigned short Nout = 0, Nx, orig_Nx;
unsigned short maxOutput;
int total_inCount = 0;
int c, i, Ycount, last;
bool first_pass = TRUE;
/* Account for increased filter gain when using factors less than 1 */
if (_factor < 1)
LpScl = (unsigned short)(LpScl*_factor + 0.5);
/* Calc reach of LP filter wing & give some creeping room */
Xoff = (unsigned short)(((Nmult+1)/2.0) * MAX(1.0,1.0/_factor) + 10);
if (IBUFFSIZE < 2*Xoff) /* Check input buffer size */
return err_ret("IBUFFSIZE (or factor) is too small");
Nx = IBUFFSIZE - 2*Xoff; /* # of samples to process each iteration */
last = 0; /* Have not read last input sample yet */
Ycount = 0; /* Current sample and length of output file */
Xp = Xoff; /* Current "now"-sample pointer for input */
Xread = Xoff; /* Position in input array to read into */
if (_initial == TRUE)
_Time = (Xoff<<Np); /* Current-time pointer for converter */
do {
if (!last) /* If haven't read last sample yet */
{
last = readData(inCount, inArray, _II,
IBUFFSIZE, (int)Xread,first_pass);
first_pass = FALSE;
if (last && (last-Xoff<Nx)) { /* If last sample has been read... */
Nx = last-Xoff; /* ...calc last sample affected by filter */
if (Nx <= 0)
break;
}
}
if ( (outCount-Ycount) > (OBUFFSIZE - (2*Xoff*_factor)) )
maxOutput = OBUFFSIZE - (unsigned short)(2*Xoff*_factor);
else
maxOutput = outCount-Ycount;
for (c = 0; c < _nChans; c++)
{
orig_Nx = Nx;
Time2 = _Time;
/* Resample stuff in input buffer */
if (_factor >= 1) { /* SrcUp() is faster if we can use it */
Nout=SrcUp(_II[c],_JJ[c],_factor,
&Time2,Nx,maxOutput,Nwing,LpScl,Imp,ImpD,interpFilt);
}
else {
Nout=SrcUD(_II[c],_JJ[c],_factor,
&Time2,Nx,maxOutput,Nwing,LpScl,Imp,ImpD,interpFilt);
}
}
_Time = Time2;
_Time -= (Nx<<Np); /* Move converter Nx samples back in time */
Xp += Nx; /* Advance by number of samples processed */
#if 0
Ncreep = (Time>>Np) - Xoff; /* Calc time accumulation in Time */
if (Ncreep) {
Time -= (Ncreep<<Np); /* Remove time accumulation */
Xp += Ncreep; /* and add it to read pointer */
}
#endif
if (last) { /* If near end of sample... */
last -= Xp; /* ...keep track were it ends */
if (!last) /* Lengthen input by 1 sample if... */
last++; /* ...needed to keep flag TRUE */
}
Ycount += Nout;
if (Ycount > outCount) {
Nout -= (Ycount - outCount);
Ycount = outCount;
}
if (Nout > OBUFFSIZE) /* Check to see if output buff overflowed */
return err_ret("Output array overflow");
for (c = 0; c < _nChans; c++)
{
for (i = 0; i < Nout; i++)
{
outArray[c * outCount + i + Ycount - Nout] = _JJ[c][i];
}
}
int act_incount = (int)Nx;
for (c = 0; c < _nChans; c++)
{
for (i=0; i<IBUFFSIZE-act_incount+Xoff; i++) { /* Copy part of input signal */
_II[c][i] = _II[c][i+act_incount]; /* that must be re-used */
}
}
Xread = IBUFFSIZE - Nx; /* Pos in input buff to read new data into */
Xp = Xoff;
total_inCount += Nx;
} while (Ycount < outCount); /* Continue until done */
inCount = total_inCount;
return(Ycount); /* Return # of samples in output file */
}
int
aflibConverter::FilterUp(
short Imp[],
short ImpD[],
unsigned short Nwing,
bool Interp,
short *Xp,
short Ph,
short Inc)
{
short *Hp, *Hdp = NULL, *End;
short a = 0;
int v, t;
v=0;
Hp = &Imp[Ph>>Na];
End = &Imp[Nwing];
if (Interp)
{
Hdp = &ImpD[Ph>>Na];
a = Ph & Amask;
}
if (Inc == 1) /* If doing right wing... */
{ /* ...drop extra coeff, so when Ph is */
End--; /* 0.5, we don't do too many mult's */
if (Ph == 0) /* If the phase is zero... */
{ /* ...then we've already skipped the */
Hp += Npc; /* first sample, so we must also */
Hdp += Npc; /* skip ahead in Imp[] and ImpD[] */
}
}
if (Interp)
{
while (Hp < End)
{
t = *Hp; /* Get filter coeff */
t += (((int)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
Hdp += Npc; /* Filter coeff differences step */
t *= *Xp; /* Mult coeff by input sample */
if (t & (1<<(Nhxn-1))) /* Round, if needed */
t += (1<<(Nhxn-1));
t >>= Nhxn; /* Leave some guard bits, but come back some */
v += t; /* The filter output */
Hp += Npc; /* Filter coeff step */
Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
}
}
else
{
while (Hp < End)
{
t = *Hp; /* Get filter coeff */
t *= *Xp; /* Mult coeff by input sample */
if (t & (1<<(Nhxn-1))) /* Round, if needed */
t += (1<<(Nhxn-1));
t >>= Nhxn; /* Leave some guard bits, but come back some */
v += t; /* The filter output */
Hp += Npc; /* Filter coeff step */
Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
}
}
return(v);
}
int
aflibConverter::FilterUD(
short Imp[],
short ImpD[],
unsigned short Nwing,
bool Interp,
short *Xp,
short Ph,
short Inc,
unsigned short dhb)
{
short a;
short *Hp, *Hdp, *End;
int v, t;
unsigned int Ho;
v=0;
Ho = (Ph*(unsigned int)dhb)>>Np;
End = &Imp[Nwing];
if (Inc == 1) /* If doing right wing... */
{ /* ...drop extra coeff, so when Ph is */
End--; /* 0.5, we don't do too many mult's */
if (Ph == 0) /* If the phase is zero... */
Ho += dhb; /* ...then we've already skipped the */
} /* first sample, so we must also */
/* skip ahead in Imp[] and ImpD[] */
if (Interp)
{
while ((Hp = &Imp[Ho>>Na]) < End)
{
t = *Hp; /* Get IR sample */
Hdp = &ImpD[Ho>>Na]; /* get interp (lower Na) bits from diff table*/
a = Ho & Amask; /* a is logically between 0 and 1 */
t += (((int)*Hdp)*a)>>Na; /* t is now interp'd filter coeff */
t *= *Xp; /* Mult coeff by input sample */
if (t & 1<<(Nhxn-1)) /* Round, if needed */
t += 1<<(Nhxn-1);
t >>= Nhxn; /* Leave some guard bits, but come back some */
v += t; /* The filter output */
Ho += dhb; /* IR step */
Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
}
}
else
{
while ((Hp = &Imp[Ho>>Na]) < End)
{
t = *Hp; /* Get IR sample */
t *= *Xp; /* Mult coeff by input sample */
if (t & 1<<(Nhxn-1)) /* Round, if needed */
t += 1<<(Nhxn-1);
t >>= Nhxn; /* Leave some guard bits, but come back some */
v += t; /* The filter output */
Ho += dhb; /* IR step */
Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */
}
}
return(v);
}

View File

@ -0,0 +1,236 @@
/*
* Copyright: (C) 2000 Julius O. Smith
*
* 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Julius O. Smith jos@ccrma.stanford.edu
*
*/
/* This code was modified by Bruce Forsberg (forsberg@tns.net) to make it
into a C++ class
*/
#ifndef _AFLIBCONVERTER_H_
#define _AFLIBCONVERTER_H_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef MAX
#define MAX(x,y) ((x)>(y) ?(x):(y))
#endif
#ifndef MIN
#define MIN(x,y) ((x)<(y) ?(x):(y))
#endif
#define MAX_HWORD (32767)
#define MIN_HWORD (-32768)
#define IBUFFSIZE 4096 /* Input buffer size */
/*! \class aflibConverter
\brief Provides sample rate conversion.
This class will perform audio resampling. With the constructor you can choose the
type of resampling to be done. Simple linear interpolation can be done by setting
linear_interpolation to be TRUE in the constructor. The other two flags are
ignored if this is set. If linear_interpolation is FALSE then some form of filtering
will be done. IF high_quality is FALSE then a small filter will be performed.
If high_quality is TRUE then a large filter (higher quality) will be performed. For
both the small and large filters another parameter can be specified, filter_interpolation.
With filter_interpolation set then the filter coefficients used for both the small and
large filtering will be interpolated as well.
This class was designed to stream audio data. It also expects audio data as 16 bit values.
Each time a new stream is started some initialization needs to be done. Thus the function
initialize should be called to initialize everything. This initialize function will set
the conversion factor as well as a multiplecation factor for volume. The volume only
applies to the small and large filter. Since this filter uses a history of the audio data
it is possible for it to vary in amplitude. This allows users to scale the data. This
class will work on any number of channels. Once everything is specified then resample
should be called as many times as is necessary to process all the data. The value
inCount will be returned indicating how many inArray samples were actually used to
produce the output. This value can be used to indicate where the next block of
inArray data should start. The resample function is driven by the outCount value
specified. The inArray should contain at least:
outCount / factor + extra_samples.
extra_samples depends on the type of filtering done. As a rule of thumb 50 should be
adequate for any type of filter.
*/
class aflibData;
class aflibConverter {
public:
// Available contructors and destructors
aflibConverter (
bool high_quality,
bool linear_interpolation,
bool filter_interpolation);
~aflibConverter();
void
initialize(
double factor, /* factor = Sndout/Sndin */
int channels, /* number of sound channels */
double volume = 1.0); /* factor to multiply amplitude */
int
resample( /* number of output samples returned */
int& inCount, /* number of input samples to convert */
int outCount, /* number of output samples to compute */
short inArray[], /* input array data (length inCount * nChans) */
short outArray[]);/* output array data (length outCount * nChans) */
private:
aflibConverter();
aflibConverter(const aflibConverter& op);
const aflibConverter&
operator=(const aflibConverter& op);
int
err_ret(const char *s);
void
deleteMemory();
int
readData(
int inCount, /* _total_ number of frames in input file */
short inArray[], /* input data */
short *outPtr[], /* array receiving chan samps */
int dataArraySize, /* size of these arrays */
int Xoff, /* read into input array starting at this index */
bool init_count);
inline short
WordToHword(int v, int scl)
{
short out;
int llsb = (1<<(scl-1));
v += llsb; /* round */
v >>= scl;
if (v>MAX_HWORD) {
v = MAX_HWORD;
} else if (v < MIN_HWORD) {
v = MIN_HWORD;
}
out = (short) v;
return out;
};
int
SrcLinear(
short X[],
short Y[],
double factor,
unsigned int *Time,
unsigned short& Nx,
unsigned short Nout);
int
SrcUp(
short X[],
short Y[],
double factor,
unsigned int *Time,
unsigned short& Nx,
unsigned short Nout,
unsigned short Nwing,
unsigned short LpScl,
short Imp[],
short ImpD[],
bool Interp);
int
SrcUD(
short X[],
short Y[],
double factor,
unsigned int *Time,
unsigned short& Nx,
unsigned short Nout,
unsigned short Nwing,
unsigned short LpScl,
short Imp[],
short ImpD[],
bool Interp);
int
FilterUp(
short Imp[],
short ImpD[],
unsigned short Nwing,
bool Interp,
short *Xp,
short Ph,
short Inc);
int
FilterUD(
short Imp[],
short ImpD[],
unsigned short Nwing,
bool Interp,
short *Xp,
short Ph,
short Inc,
unsigned short dhb);
int
resampleFast( /* number of output samples returned */
int& inCount, /* number of input samples to convert */
int outCount, /* number of output samples to compute */
short inArray[], /* input array data (length inCount * nChans) */
short outArray[]);/* output array data (length outCount * nChans) */
int
resampleWithFilter( /* number of output samples returned */
int& inCount, /* number of input samples to convert */
int outCount, /* number of output samples to compute */
short inArray[], /* input array data (length inCount * nChans) */
short outArray[], /* output array data (length outCount * nChans) */
short Imp[], short ImpD[],
unsigned short LpScl, unsigned short Nmult, unsigned short Nwing);
static short SMALL_FILTER_IMP[];
static short LARGE_FILTER_IMP[];
bool interpFilt;
bool largeFilter;
bool linearInterp;
short ** _II;
short ** _JJ;
unsigned int _Time;
double _factor;
int _nChans;
bool _initial;
double _vol;
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,229 @@
/*
Copyright (C) 2000 Stefan Westerfeld
stefan@space.twc.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "aflibDebug.h"
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
static int aflib_debug_level = ::aflibDebug::lInfo;
static bool aflib_debug_abort = false;
static const char *aflib_debug_prefix = "";
static char *messageAppName = 0;
/*
static char* status_strs[] =
{
"Success",
"Error Open",
"Unsupported",
"AFLIB_ERROR_INITIALIZATION_FAILURE",
"AFLIB_NOT_FOUND",
"AFLIB_END_OF_FILE",
"AFLIB_NO_DATA",
0
};
static char* data_size_strs[] =
{
"UNDEFINED",
"8 bit signed",
"8 bit unsigned",
"16 bit signed",
"16 bit unsigned",
"32 bit signed",
"32 bit unsigned",
0
};
static char* data_endian_strs[] =
{
"UNDEFINED",
"ENDIAN_LITTLE",
"ENDIAN_BIG",
0
};
*/
/*
* Call the graphical application to display a message, if
* defined. Otherwise, send to standard error. Debug messages are
* always sent to standard error because they tend to be very verbose.
* Note that the external application is run in the background to
* avoid blocking the sound server.
*/
void output_message(::aflibDebug::Level level, const char *msg) {
char buff[1024];
/* default to text output if no message app is defined or if it is a debug message. */
if (messageAppName == 0 || !strcmp(messageAppName, "") || (level == ::aflibDebug::lDebug))
{
fprintf(stderr, "%s\n", msg);
return;
}
switch (level) {
case ::aflibDebug::lFatal:
sprintf(buff, "%s -e \"aflib fatal error:\n\n%s\" &", messageAppName, msg);
break;
case ::aflibDebug::lWarning:
sprintf(buff, "%s -w \"aflib warning message:\n\n%s\" &", messageAppName, msg);
break;
case ::aflibDebug::lInfo:
sprintf(buff, "%s -i \"aflib informational message:\n\n%s\" &", messageAppName, msg);
break;
default:
break; // avoid compile warning
}
int r = system(buff);
if (r<0) fprintf(stderr, "aflibDebug, system() failed\n");
}
/*
* Display a message using output_message. If the message is the same
* as the previous one, just increment a count but don't display
* it. This prevents flooding the user with duplicate warnings. If the
* message is not the same as the previous one, then we report the
* previously repeated message (if any) and reset the last message and
* count.
*/
void display_message(::aflibDebug::Level level, const char *msg) {
static char lastMsg[1024];
static ::aflibDebug::Level lastLevel;
static int msgCount = 0;
if (!strncmp(msg, lastMsg, 1024))
{
msgCount++;
} else {
if (msgCount > 0)
{
char buff[1024];
sprintf(buff, "%s\n(The previous message was repeated %d times.)", lastMsg, msgCount);
output_message(lastLevel, buff);
}
strncpy(lastMsg, msg, 1024);
lastLevel = level;
msgCount = 0;
output_message(level, msg);
}
}
static class DebugInitFromEnv {
public:
DebugInitFromEnv() {
const char *env = getenv("AFLIB_DEBUG");
if(env)
{
if(strcmp(env,"debug") == 0)
aflib_debug_level = ::aflibDebug::lDebug;
else if(strcmp(env,"info") == 0)
aflib_debug_level = ::aflibDebug::lInfo;
else if(strcmp(env,"warning") == 0)
aflib_debug_level = ::aflibDebug::lWarning;
else if(strcmp(env,"quiet") == 0)
aflib_debug_level = ::aflibDebug::lFatal;
else
{
fprintf(stderr,
"AFLIB_DEBUG must be one of debug,info,warning,quiet\n");
}
}
env = getenv("AFLIB_DEBUG_ABORT");
if(env)
aflib_debug_abort = true;
}
}
debugInitFromEnv;
void aflibDebug::init(const char *prefix, Level level)
{
aflib_debug_level = level;
aflib_debug_prefix = prefix;
}
void aflibDebug::fatal(const char *fmt, ...)
{
char buff[1024];
va_list ap;
va_start(ap, fmt);
vsprintf(buff, fmt, ap);
va_end(ap);
display_message(::aflibDebug::lFatal, buff);
if(aflib_debug_abort) abort();
exit(1);
}
void aflibDebug::warning(const char *fmt, ...)
{
if(lWarning >= aflib_debug_level)
{
char buff[1024];
va_list ap;
va_start(ap, fmt);
vsprintf(buff, fmt, ap);
va_end(ap);
display_message(::aflibDebug::lWarning, buff);
}
}
void aflibDebug::info(const char *fmt, ...)
{
if(lInfo >= aflib_debug_level)
{
char buff[1024];
va_list ap;
va_start(ap, fmt);
vsprintf(buff, fmt, ap);
va_end(ap);
display_message(::aflibDebug::lInfo, buff);
}
}
void aflibDebug::debug(const char *fmt, ...)
{
if(lDebug >= aflib_debug_level)
{
char buff[1024];
va_list ap;
va_start(ap, fmt);
vsprintf(buff, fmt, ap);
va_end(ap);
display_message(::aflibDebug::lDebug, buff);
}
}
void aflibDebug::messageApp(const char *appName)
{
messageAppName = (char*) realloc(messageAppName, strlen(appName)+1);
strcpy(messageAppName, appName);
}

View File

@ -0,0 +1,118 @@
/*
Copyright (C) 2000 Stefan Westerfeld
stefan@space.twc.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Some inspiration taken from glib.
Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GLib Team and others 1997-1999.
*/
#ifndef _AFLIBDEBUG_H_
#define _AFLIBDEBUG_H_
/*
* BC - Status (2000-09-30): Debug.
*
* Collection class, no instance, no members. Thus binary compatible (will
* be kept).
*/
#define aflib_fatal ::aflibDebug::fatal
#define aflib_warning ::aflibDebug::warning
#define aflib_info ::aflibDebug::info
#define aflib_debug ::aflibDebug::debug
/* source compatibility with older sources */
#define aflibdebug ::aflibDebug::debug
#define setaflibdebug(x) aflib_warning("setaflibdebug is obsolete")
#ifdef __GNUC__
#define aflib_return_if_fail(expr) \
if (!(expr)) \
{ \
aflib_warning ("file %s: line %d (%s): assertion failed: (%s)", \
__FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
return; \
}
#define aflib_return_val_if_fail(expr,val) \
if (!(expr)) \
{ \
aflib_warning ("file %s: line %d (%s): assertion failed: (%s)", \
__FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
return (val); \
}
#define aflib_assert(expr) \
if (!(expr)) \
aflib_fatal ("file %s: line %d (%s): assertion failed: (%s)", \
__FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
#else
#define aflib_return_if_fail(expr) \
if (!(expr)) \
{ \
aflib_warning ("file %s: line %d: assertion failed: (%s)", \
__FILE__, __LINE__, #expr); \
return; \
}
#define aflib_return_val_if_fail(expr,val) \
if (!(expr)) \
{ \
aflib_warning ("file %s: line %d: assertion failed: (%s)", \
__FILE__, __LINE__, #expr); \
return (val); \
}
#define aflib_assert(expr) \
if (!(expr)) \
aflib_fatal ("file %s: line %d: assertion failed: (%s)", \
__FILE__, __LINE__, #expr); \
#endif
class aflibDebug {
public:
enum Level { lFatal = 3, lWarning = 2, lInfo = 1, lDebug = 0 };
/**
* Initializes at which is the minimum level to react to. If you
* call this, call this before creating the Arts::Dispatcher object.
*/
static void init(const char *prefix, Level level);
static void fatal(const char *fmt,...); // print on stderr & abort
static void warning(const char *fmt,...); // print on stderr
static void info(const char *fmt,...); // print on stdout
static void debug(const char *fmt,...); // print on stdout
/**
* This method sets the name of an external application to
* display messages graphically.
*/
static void messageApp(const char *appName);
};
#endif

Some files were not shown because too many files have changed in this diff Show More