Fixed web browser thanks to ArminW/Imprudence

This commit is contained in:
Siana Gearz
2010-12-24 22:22:20 +01:00
parent 80fe022718
commit 1d6bb3f3ea
59 changed files with 3505 additions and 1140 deletions

View File

@@ -1,68 +1,504 @@
http://www.gnu.org/copyleft/lgpl.html
GNU LESSER GENERAL PUBLIC LICENSE
GStreamer
Copyright (C) 1999-2008 GStreamer authors
Version 3, 29 June 2007
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.
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
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.
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, .this License. refers to version 3 of the GNU Lesser General Public License, and the .GNU GPL. refers to version 3 of the GNU General Public License.
----------------------------------------------------------------------
.The Library. refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.
An .Application. is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library.
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
A .Combined Work. is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the .Linked Version..
Copyright (C) 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
The .Minimal Corresponding Source. for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
The .Corresponding Application Code. for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
Preamble
You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version:
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
* a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or
* b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy.
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
this service 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.
3. Object Code Incorporating Material from Library Header Files.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following:
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
* a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License.
* b) Accompany the object code with a copy of the GNU GPL and this license document.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
4. Combined Works.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following:
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
* a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License.
* b) Accompany the Combined Work with a copy of the GNU GPL and this license document.
* c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document.
* d) Do one of the following:
o 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.
o 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version.
* e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
5. Combined Libraries.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following:
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
* a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License.
* b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
6. Revised Versions of the GNU Lesser General Public License.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License .or any later version. applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation.
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -7,14 +7,15 @@ if (STANDALONE)
pkg_check_modules(DBUSGLIB REQUIRED dbus-glib-1)
elseif (LINUX)
use_prebuilt_binary(glib) # dbusglib needs glib
use_prebuilt_binary(dbusglib)
set(DBUSGLIB_FOUND ON FORCE BOOL)
set(DBUSGLIB_INCLUDE_DIRS
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0
)
# We don't need to explicitly link against dbus-glib itself, because
# the viewer probes for the system's copy at runtime.
set(DBUSGLIB_LIBRARIES
dbus-glib-1
gobject-2.0
glib-2.0
)

View File

@@ -7,6 +7,7 @@ if (STANDALONE)
pkg_check_modules(GSTREAMER010 REQUIRED gstreamer-0.10)
pkg_check_modules(GSTREAMER010_PLUGINS_BASE REQUIRED gstreamer-plugins-base-0.10)
elseif (LINUX)
use_prebuilt_binary(glib) # gstreamer needs glib
use_prebuilt_binary(gstreamer)
# possible libxml should have its own .cmake file instead
use_prebuilt_binary(libxml)

View File

@@ -32,6 +32,7 @@ if (STANDALONE)
endforeach(pkg)
else (STANDALONE)
if (NOT DARWIN)
use_prebuilt_binary(glib) # gtk-etc needs glib
use_prebuilt_binary(gtk-atk-pango-glib)
endif (NOT DARWIN)
if (LINUX)
@@ -49,11 +50,14 @@ else (STANDALONE)
pangoft2-1.0
pangox-1.0
pangoxft-1.0
pangocairo-1.0
)
endif (LINUX)
include_directories (
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/cairo
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/pixman-1
${LIBS_PREBUILT_DIR}/include
)
foreach(include ${${LL_ARCH}_INCLUDES})

View File

@@ -3,6 +3,7 @@
project(llplugin)
include(00-Common)
include(CURL)
include(LLCommon)
include(LLImage)
include(LLMath)
@@ -19,10 +20,12 @@ include_directories(
${LLRENDER_INCLUDE_DIRS}
${LLXML_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
${LLQTWEBKIT_INCLUDE_DIR}
)
set(llplugin_SOURCE_FILES
llpluginclassmedia.cpp
llplugincookiestore.cpp
llplugininstance.cpp
llpluginmessage.cpp
llpluginmessagepipe.cpp
@@ -36,6 +39,7 @@ set(llplugin_HEADER_FILES
llpluginclassmedia.h
llpluginclassmediaowner.h
llplugincookiestore.h
llplugininstance.h
llpluginmessage.h
llpluginmessageclasses.h
@@ -48,20 +52,32 @@ set(llplugin_HEADER_FILES
set_source_files_properties(${llplugin_HEADER_FILES}
PROPERTIES HEADER_FILE_ONLY TRUE)
if(WORD_SIZE EQUAL 64)
if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4)
if(WINDOWS)
add_definitions(/FIXED:NO)
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
add_definitions(-fPIC)
endif(WINDOWS)
endif (WORD_SIZE EQUAL 64)
endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4)
list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES})
add_library (llplugin ${llplugin_SOURCE_FILES})
add_dependencies(llplugin
prepare
)
add_subdirectory(slplugin)
# # Add tests
# include(LLAddBuildTest)
# # UNIT TESTS
# SET(llplugin_TEST_SOURCE_FILES
# llplugincookiestore.cpp
# )
#
# # llplugincookiestore has a dependency on curl, so we need to link the curl library into the test.
# set_source_files_properties(
# llplugincookiestore.cpp
# PROPERTIES
# LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}"
# )
#
# LL_ADD_PROJECT_UNIT_TESTS(llplugin "${llplugin_TEST_SOURCE_FILES}")

93
indra/llplugin/llpluginclassmedia.cpp Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginclassmedia.cpp
* @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"
@@ -36,6 +39,8 @@
#include "llpluginclassmedia.h"
#include "llpluginmessageclasses.h"
#include "llqtwebkit.h"
static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
static int nextPowerOf2( int value )
@@ -54,23 +59,31 @@ LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
mOwner = owner;
mPlugin = NULL;
reset();
//debug use
mDeleteOK = true ;
}
LLPluginClassMedia::~LLPluginClassMedia()
{
llassert_always(mDeleteOK) ;
reset();
}
bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path)
bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug)
{
LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
LL_DEBUGS("Plugin") << "user_data_path: " << user_data_path << LL_ENDL;
mPlugin = new LLPluginProcessParent(this);
mPlugin->setSleepTime(mSleepTime);
mPlugin->init(launcher_filename, plugin_filename, debug, user_data_path);
// Queue up the media init message -- it will be sent after all the currently queued messages.
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
sendMessage(message);
mPlugin->init(launcher_filename, plugin_filename, debug);
return true;
}
@@ -101,6 +114,8 @@ void LLPluginClassMedia::reset()
mSetMediaHeight = -1;
mRequestedMediaWidth = 0;
mRequestedMediaHeight = 0;
mRequestedTextureWidth = 0;
mRequestedTextureHeight = 0;
mFullMediaWidth = 0;
mFullMediaHeight = 0;
mTextureWidth = 0;
@@ -123,7 +138,8 @@ void LLPluginClassMedia::reset()
mCanPaste = false;
mMediaName.clear();
mMediaDescription.clear();
mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
// media_browser class
mNavigateURI.clear();
mNavigateResultCode = -1;
@@ -132,6 +148,8 @@ void LLPluginClassMedia::reset()
mHistoryForwardAvailable = false;
mStatusText.clear();
mProgressPercent = 0;
mClickURL.clear();
mClickTarget.clear();
// media_time class
mCurrentTime = 0.0f;
@@ -147,7 +165,7 @@ void LLPluginClassMedia::idle(void)
mPlugin->idle();
}
if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL))
if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()))
{
// Can't process a size change at this time
}
@@ -233,6 +251,10 @@ void LLPluginClassMedia::idle(void)
message.setValueS32("height", mRequestedMediaHeight);
message.setValueS32("texture_width", mRequestedTextureWidth);
message.setValueS32("texture_height", mRequestedTextureHeight);
message.setValueReal("background_r", mBackgroundColor.mV[VX]);
message.setValueReal("background_g", mBackgroundColor.mV[VY]);
message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
message.setValueReal("background_a", mBackgroundColor.mV[VW]);
mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
@@ -420,6 +442,12 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
{
if(type == MOUSE_EVENT_MOVE)
{
if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
{
// Don't queue up mouse move events that can't be delivered.
return;
}
if((x == mLastMouseX) && (y == mLastMouseY))
{
// Don't spam unnecessary mouse move events.
@@ -458,7 +486,7 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
sendMessage(message);
}
bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers)
bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
{
bool result = true;
@@ -515,6 +543,7 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
message.setValueS32("key", key_code);
message.setValue("modifiers", translateModifiers(modifiers));
message.setValueLLSD("native_key_data", native_key_data);
sendMessage(message);
}
@@ -533,12 +562,13 @@ void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
sendMessage(message);
}
bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers)
bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
message.setValue("text", text);
message.setValue("modifiers", translateModifiers(modifiers));
message.setValueLLSD("native_key_data", native_key_data);
sendMessage(message);
@@ -663,6 +693,34 @@ void LLPluginClassMedia::paste()
sendMessage(message);
}
void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
message.setValue("path", user_data_path);
sendMessage(message);
}
void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
message.setValue("language", language_code);
sendMessage(message);
}
void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
message.setValueBoolean("enable", enabled);
sendMessage(message);
}
void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
message.setValueBoolean("enable", enabled);
sendMessage(message);
}
/* virtual */
void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
@@ -923,6 +981,13 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mClickTarget.clear();
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
}
else if(message_name == "cookie_set")
{
if(mOwner)
{
mOwner->handleCookieSet(this, message.getValue("cookie"));
}
}
else
{
LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
@@ -1006,9 +1071,17 @@ void LLPluginClassMedia::clear_cookies()
sendMessage(message);
}
void LLPluginClassMedia::set_cookies(const std::string &cookies)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
message.setValue("cookies", cookies);
sendMessage(message);
}
void LLPluginClassMedia::enable_cookies(bool enable)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
message.setValueBoolean("enable", enable);
sendMessage(message);
}

39
indra/llplugin/llpluginclassmedia.h Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginclassmedia.h
* @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINCLASSMEDIA_H
@@ -38,7 +41,7 @@
#include "llrect.h"
#include "llpluginclassmediaowner.h"
#include <queue>
#include "v4color.h"
class LLPluginClassMedia : public LLPluginProcessParentOwner
{
@@ -48,7 +51,9 @@ public:
virtual ~LLPluginClassMedia();
// local initialization, called by the media manager when creating a source
virtual bool init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path);
virtual bool init(const std::string &launcher_filename,
const std::string &plugin_filename,
bool debug);
// undoes everything init() didm called by the media manager when destroying a source
virtual void reset();
@@ -85,6 +90,8 @@ public:
void setSize(int width, int height);
void setAutoScale(bool auto_scale);
void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; };
// Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent.
// This will initially be false, and will also be false for some time after setSize while the resize is processed.
// Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values
@@ -111,12 +118,12 @@ public:
KEY_EVENT_REPEAT
}EKeyEventType;
bool keyEvent(EKeyEventType type, int key_code, MASK modifiers);
bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data);
void scrollEvent(int x, int y, MASK modifiers);
// Text may be unicode (utf8 encoded)
bool textInput(const std::string &text, MASK modifiers);
bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data);
void loadURI(const std::string &uri);
@@ -170,6 +177,12 @@ public:
void paste();
bool canPaste() const { return mCanPaste; };
// These can be called before init(), and they will be queued and sent before the media init message.
void setUserDataPath(const std::string &user_data_path);
void setLanguageCode(const std::string &language_code);
void setPluginsEnabled(const bool enabled);
void setJavascriptEnabled(const bool enabled);
///////////////////////////////////
// media browser class functions
@@ -178,6 +191,7 @@ public:
void focus(bool focused);
void clear_cache();
void clear_cookies();
void set_cookies(const std::string &cookies);
void enable_cookies(bool enable);
void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0);
void browse_stop();
@@ -211,6 +225,7 @@ public:
// This is valid after MEDIA_EVENT_CLICK_LINK_HREF
std::string getClickTarget() const { return mClickTarget; };
std::string getMediaName() const { return mMediaName; };
std::string getMediaDescription() const { return mMediaDescription; };
@@ -327,6 +342,8 @@ protected:
std::string mMediaName;
std::string mMediaDescription;
LLColor4 mBackgroundColor;
/////////////////////////////////////////
// media_browser class
std::string mNavigateURI;
@@ -347,6 +364,14 @@ protected:
F64 mCurrentRate;
F64 mLoadedDuration;
//--------------------------------------
//debug use only
//
private:
bool mDeleteOK ;
public:
void setDeleteOK(bool flag) { mDeleteOK = flag ;}
//--------------------------------------
};
#endif // LL_LLPLUGINCLASSMEDIA_H

11
indra/llplugin/llpluginclassmediaowner.h Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginclassmediaowner.h
* @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINCLASSMEDIAOWNER_H
@@ -38,6 +41,7 @@
#include <queue>
class LLPluginClassMedia;
class LLPluginCookieStore;
class LLPluginClassMediaOwner
{
@@ -77,6 +81,7 @@ public:
virtual ~LLPluginClassMediaOwner() {};
virtual void handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent /*event*/) {};
virtual void handleCookieSet(LLPluginClassMedia* /*self*/, const std::string &/*cookie*/) {};
};
#endif // LL_LLPLUGINCLASSMEDIAOWNER_H

View File

@@ -0,0 +1,671 @@
/**
* @file llplugincookiestore.cpp
* @brief LLPluginCookieStore provides central storage for http cookies used by plugins
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"
#include "indra_constants.h"
#include "llplugincookiestore.h"
#include <iostream>
// for curl_getdate() (apparently parsing RFC 1123 dates is hard)
#include <curl/curl.h>
LLPluginCookieStore::LLPluginCookieStore():
mHasChangedCookies(false)
{
}
LLPluginCookieStore::~LLPluginCookieStore()
{
clearCookies();
}
LLPluginCookieStore::Cookie::Cookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end):
mCookie(s, cookie_start, cookie_end - cookie_start),
mNameStart(0), mNameEnd(0),
mValueStart(0), mValueEnd(0),
mDomainStart(0), mDomainEnd(0),
mPathStart(0), mPathEnd(0),
mDead(false), mChanged(true)
{
}
LLPluginCookieStore::Cookie *LLPluginCookieStore::Cookie::createFromString(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, const std::string &host)
{
Cookie *result = new Cookie(s, cookie_start, cookie_end);
if(!result->parse(host))
{
delete result;
result = NULL;
}
return result;
}
std::string LLPluginCookieStore::Cookie::getKey() const
{
std::string result;
if(mDomainEnd > mDomainStart)
{
result += mCookie.substr(mDomainStart, mDomainEnd - mDomainStart);
}
result += ';';
if(mPathEnd > mPathStart)
{
result += mCookie.substr(mPathStart, mPathEnd - mPathStart);
}
result += ';';
result += mCookie.substr(mNameStart, mNameEnd - mNameStart);
return result;
}
bool LLPluginCookieStore::Cookie::parse(const std::string &host)
{
bool first_field = true;
std::string::size_type cookie_end = mCookie.size();
std::string::size_type field_start = 0;
LL_DEBUGS("CookieStoreParse") << "parsing cookie: " << mCookie << LL_ENDL;
while(field_start < cookie_end)
{
// Finding the start of the next field requires honoring special quoting rules
// see the definition of 'quoted-string' in rfc2616 for details
std::string::size_type next_field_start = findFieldEnd(field_start);
// The end of this field should not include the terminating ';' or any trailing whitespace
std::string::size_type field_end = mCookie.find_last_not_of("; ", next_field_start);
if(field_end == std::string::npos || field_end < field_start)
{
// This field was empty or all whitespace. Set end = start so it shows as empty.
field_end = field_start;
}
else if (field_end < next_field_start)
{
// we actually want the index of the char _after_ what 'last not of' found
++field_end;
}
// find the start of the actual name (skip separator and possible whitespace)
std::string::size_type name_start = mCookie.find_first_not_of("; ", field_start);
if(name_start == std::string::npos || name_start > next_field_start)
{
// Again, nothing but whitespace.
name_start = field_start;
}
// the name and value are separated by the first equals sign
std::string::size_type name_value_sep = mCookie.find_first_of("=", name_start);
if(name_value_sep == std::string::npos || name_value_sep > field_end)
{
// No separator found, so this is a field without an =
name_value_sep = field_end;
}
// the name end is before the name-value separator
std::string::size_type name_end = mCookie.find_last_not_of("= ", name_value_sep);
if(name_end == std::string::npos || name_end < name_start)
{
// I'm not sure how we'd hit this case... it seems like it would have to be an empty name.
name_end = name_start;
}
else if (name_end < name_value_sep)
{
// we actually want the index of the char _after_ what 'last not of' found
++name_end;
}
// Value is between the name-value sep and the end of the field.
std::string::size_type value_start = mCookie.find_first_not_of("= ", name_value_sep);
if(value_start == std::string::npos || value_start > field_end)
{
// All whitespace or empty value
value_start = field_end;
}
std::string::size_type value_end = mCookie.find_last_not_of("; ", field_end);
if(value_end == std::string::npos || value_end < value_start)
{
// All whitespace or empty value
value_end = value_start;
}
else if (value_end < field_end)
{
// we actually want the index of the char _after_ what 'last not of' found
++value_end;
}
LL_DEBUGS("CookieStoreParse")
<< " field name: \"" << mCookie.substr(name_start, name_end - name_start)
<< "\", value: \"" << mCookie.substr(value_start, value_end - value_start) << "\""
<< LL_ENDL;
// See whether this field is one we know
if(first_field)
{
// The first field is the name=value pair
mNameStart = name_start;
mNameEnd = name_end;
mValueStart = value_start;
mValueEnd = value_end;
first_field = false;
}
else
{
// Subsequent fields must come from the set in rfc2109
if(matchName(name_start, name_end, "expires"))
{
std::string date_string(mCookie, value_start, value_end - value_start);
// If the cookie contains an "expires" field, it MUST contain a parsable date.
// HACK: LLDate apparently can't PARSE an rfc1123-format date, even though it can GENERATE one.
// The curl function curl_getdate can do this, but I'm hesitant to unilaterally introduce a curl dependency in LLDate.
#if 1
time_t date = curl_getdate(date_string.c_str(), NULL );
mDate.secondsSinceEpoch((F64)date);
LL_DEBUGS("CookieStoreParse") << " expire date parsed to: " << mDate.asRFC1123() << LL_ENDL;
#else
// This doesn't work (rfc1123-format dates cause it to fail)
if(!mDate.fromString(date_string))
{
// Date failed to parse.
LL_WARNS("CookieStoreParse") << "failed to parse cookie's expire date: " << date << LL_ENDL;
return false;
}
#endif
}
else if(matchName(name_start, name_end, "domain"))
{
mDomainStart = value_start;
mDomainEnd = value_end;
}
else if(matchName(name_start, name_end, "path"))
{
mPathStart = value_start;
mPathEnd = value_end;
}
else if(matchName(name_start, name_end, "max-age"))
{
// TODO: how should we handle this?
}
else if(matchName(name_start, name_end, "secure"))
{
// We don't care about the value of this field (yet)
}
else if(matchName(name_start, name_end, "version"))
{
// We don't care about the value of this field (yet)
}
else if(matchName(name_start, name_end, "comment"))
{
// We don't care about the value of this field (yet)
}
else if(matchName(name_start, name_end, "httponly"))
{
// We don't care about the value of this field (yet)
}
else
{
// An unknown field is a parse failure
LL_WARNS("CookieStoreParse") << "unexpected field name: " << mCookie.substr(name_start, name_end - name_start) << LL_ENDL;
return false;
}
}
// move on to the next field, skipping this field's separator and any leading whitespace
field_start = mCookie.find_first_not_of("; ", next_field_start);
}
// The cookie MUST have a name
if(mNameEnd <= mNameStart)
return false;
// If the cookie doesn't have a domain, add the current host as the domain.
if(mDomainEnd <= mDomainStart)
{
if(host.empty())
{
// no domain and no current host -- this is a parse failure.
return false;
}
// Figure out whether this cookie ended with a ";" or not...
std::string::size_type last_char = mCookie.find_last_not_of(" ");
if((last_char != std::string::npos) && (mCookie[last_char] != ';'))
{
mCookie += ";";
}
mCookie += " domain=";
mDomainStart = mCookie.size();
mCookie += host;
mDomainEnd = mCookie.size();
LL_DEBUGS("CookieStoreParse") << "added domain (" << mDomainStart << " to " << mDomainEnd << "), new cookie is: " << mCookie << LL_ENDL;
}
// If the cookie doesn't have a path, add "/".
if(mPathEnd <= mPathStart)
{
// Figure out whether this cookie ended with a ";" or not...
std::string::size_type last_char = mCookie.find_last_not_of(" ");
if((last_char != std::string::npos) && (mCookie[last_char] != ';'))
{
mCookie += ";";
}
mCookie += " path=";
mPathStart = mCookie.size();
mCookie += "/";
mPathEnd = mCookie.size();
LL_DEBUGS("CookieStoreParse") << "added path (" << mPathStart << " to " << mPathEnd << "), new cookie is: " << mCookie << LL_ENDL;
}
return true;
}
std::string::size_type LLPluginCookieStore::Cookie::findFieldEnd(std::string::size_type start, std::string::size_type end)
{
std::string::size_type result = start;
if(end == std::string::npos)
end = mCookie.size();
bool in_quotes = false;
for(; (result < end); result++)
{
switch(mCookie[result])
{
case '\\':
if(in_quotes)
result++; // The next character is backslash-quoted. Skip over it.
break;
case '"':
in_quotes = !in_quotes;
break;
case ';':
if(!in_quotes)
return result;
break;
}
}
// If we got here, no ';' was found.
return end;
}
bool LLPluginCookieStore::Cookie::matchName(std::string::size_type start, std::string::size_type end, const char *name)
{
// NOTE: this assumes 'name' is already in lowercase. The code which uses it should be able to arrange this...
while((start < end) && (*name != '\0'))
{
if(tolower(mCookie[start]) != *name)
return false;
start++;
name++;
}
// iff both strings hit the end at the same time, they're equal.
return ((start == end) && (*name == '\0'));
}
std::string LLPluginCookieStore::getAllCookies()
{
std::stringstream result;
writeAllCookies(result);
return result.str();
}
void LLPluginCookieStore::writeAllCookies(std::ostream& s)
{
cookie_map_t::iterator iter;
for(iter = mCookies.begin(); iter != mCookies.end(); iter++)
{
// Don't return expired cookies
if(!iter->second->isDead())
{
s << (iter->second->getCookie()) << "\n";
}
}
}
std::string LLPluginCookieStore::getPersistentCookies()
{
std::stringstream result;
writePersistentCookies(result);
return result.str();
}
void LLPluginCookieStore::writePersistentCookies(std::ostream& s)
{
cookie_map_t::iterator iter;
for(iter = mCookies.begin(); iter != mCookies.end(); iter++)
{
// Don't return expired cookies or session cookies
if(!iter->second->isDead() && !iter->second->isSessionCookie())
{
s << iter->second->getCookie() << "\n";
}
}
}
std::string LLPluginCookieStore::getChangedCookies(bool clear_changed)
{
std::stringstream result;
writeChangedCookies(result, clear_changed);
return result.str();
}
void LLPluginCookieStore::writeChangedCookies(std::ostream& s, bool clear_changed)
{
if(mHasChangedCookies)
{
lldebugs << "returning changed cookies: " << llendl;
cookie_map_t::iterator iter;
for(iter = mCookies.begin(); iter != mCookies.end(); )
{
cookie_map_t::iterator next = iter;
next++;
// Only return cookies marked as "changed"
if(iter->second->isChanged())
{
s << iter->second->getCookie() << "\n";
lldebugs << " " << iter->second->getCookie() << llendl;
// If requested, clear the changed mark
if(clear_changed)
{
if(iter->second->isDead())
{
// If this cookie was previously marked dead, it needs to be removed entirely.
delete iter->second;
mCookies.erase(iter);
}
else
{
// Not dead, just mark as not changed.
iter->second->setChanged(false);
}
}
}
iter = next;
}
}
if(clear_changed)
mHasChangedCookies = false;
}
void LLPluginCookieStore::setAllCookies(const std::string &cookies, bool mark_changed)
{
clearCookies();
setCookies(cookies, mark_changed);
}
void LLPluginCookieStore::readAllCookies(std::istream& s, bool mark_changed)
{
clearCookies();
readCookies(s, mark_changed);
}
void LLPluginCookieStore::setCookies(const std::string &cookies, bool mark_changed)
{
std::string::size_type start = 0;
while(start != std::string::npos)
{
std::string::size_type end = cookies.find_first_of("\r\n", start);
if(end > start)
{
// The line is non-empty. Try to create a cookie from it.
setOneCookie(cookies, start, end, mark_changed);
}
start = cookies.find_first_not_of("\r\n ", end);
}
}
void LLPluginCookieStore::setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed)
{
std::string::size_type start = 0;
while(start != std::string::npos)
{
std::string::size_type end = cookies.find_first_of("\r\n", start);
if(end > start)
{
// The line is non-empty. Try to create a cookie from it.
setOneCookie(cookies, start, end, mark_changed, host);
}
start = cookies.find_first_not_of("\r\n ", end);
}
}
void LLPluginCookieStore::readCookies(std::istream& s, bool mark_changed)
{
std::string line;
while(s.good() && !s.eof())
{
std::getline(s, line);
if(!line.empty())
{
// Try to create a cookie from this line.
setOneCookie(line, 0, std::string::npos, mark_changed);
}
}
}
std::string LLPluginCookieStore::quoteString(const std::string &s)
{
std::stringstream result;
result << '"';
for(std::string::size_type i = 0; i < s.size(); ++i)
{
char c = s[i];
switch(c)
{
// All these separators need to be quoted in HTTP headers, according to section 2.2 of rfc 2616:
case '(': case ')': case '<': case '>': case '@':
case ',': case ';': case ':': case '\\': case '"':
case '/': case '[': case ']': case '?': case '=':
case '{': case '}': case ' ': case '\t':
result << '\\';
break;
}
result << c;
}
result << '"';
return result.str();
}
std::string LLPluginCookieStore::unquoteString(const std::string &s)
{
std::stringstream result;
bool in_quotes = false;
for(std::string::size_type i = 0; i < s.size(); ++i)
{
char c = s[i];
switch(c)
{
case '\\':
if(in_quotes)
{
// The next character is backslash-quoted. Pass it through untouched.
++i;
if(i < s.size())
{
result << s[i];
}
continue;
}
break;
case '"':
in_quotes = !in_quotes;
continue;
break;
}
result << c;
}
return result.str();
}
// The flow for deleting a cookie is non-obvious enough that I should call it out here...
// Deleting a cookie is done by setting a cookie with the same name, path, and domain, but with an expire timestamp in the past.
// (This is exactly how a web server tells a browser to delete a cookie.)
// When deleting with mark_changed set to true, this replaces the existing cookie in the list with an entry that's marked both dead and changed.
// Some time later when writeChangedCookies() is called with clear_changed set to true, the dead cookie is deleted from the list after being returned, so that the
// delete operation (in the form of the expired cookie) is passed along.
void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host)
{
Cookie *cookie = Cookie::createFromString(s, cookie_start, cookie_end, host);
if(cookie)
{
LL_DEBUGS("CookieStoreUpdate") << "setting cookie: " << cookie->getCookie() << LL_ENDL;
// Create a key for this cookie
std::string key = cookie->getKey();
// Check to see whether this cookie should have expired
if(!cookie->isSessionCookie() && (cookie->getDate() < LLDate::now()))
{
// This cookie has expired.
if(mark_changed)
{
// If we're marking cookies as changed, we should keep it anyway since we'll need to send it out with deltas.
cookie->setDead(true);
LL_DEBUGS("CookieStoreUpdate") << " marking dead" << LL_ENDL;
}
else
{
// If we're not marking cookies as changed, we don't need to keep this cookie at all.
// If the cookie was already in the list, delete it.
removeCookie(key);
delete cookie;
cookie = NULL;
LL_DEBUGS("CookieStoreUpdate") << " removing" << LL_ENDL;
}
}
if(cookie)
{
// If it already exists in the map, replace it.
cookie_map_t::iterator iter = mCookies.find(key);
if(iter != mCookies.end())
{
if(iter->second->getCookie() == cookie->getCookie())
{
// The new cookie is identical to the old -- don't mark as changed.
// Just leave the old one in the map.
delete cookie;
cookie = NULL;
LL_DEBUGS("CookieStoreUpdate") << " unchanged" << LL_ENDL;
}
else
{
// A matching cookie was already in the map. Replace it.
delete iter->second;
iter->second = cookie;
cookie->setChanged(mark_changed);
if(mark_changed)
mHasChangedCookies = true;
LL_DEBUGS("CookieStoreUpdate") << " replacing" << LL_ENDL;
}
}
else
{
// The cookie wasn't in the map. Insert it.
mCookies.insert(std::make_pair(key, cookie));
cookie->setChanged(mark_changed);
if(mark_changed)
mHasChangedCookies = true;
LL_DEBUGS("CookieStoreUpdate") << " adding" << LL_ENDL;
}
}
}
else
{
LL_WARNS("CookieStoreUpdate") << "failed to parse cookie: " << s.substr(cookie_start, cookie_end - cookie_start) << LL_ENDL;
}
}
void LLPluginCookieStore::clearCookies()
{
while(!mCookies.empty())
{
cookie_map_t::iterator iter = mCookies.begin();
delete iter->second;
mCookies.erase(iter);
}
}
void LLPluginCookieStore::removeCookie(const std::string &key)
{
cookie_map_t::iterator iter = mCookies.find(key);
if(iter != mCookies.end())
{
delete iter->second;
mCookies.erase(iter);
}
}

View File

@@ -0,0 +1,127 @@
/**
* @file llplugincookiestore.h
* @brief LLPluginCookieStore provides central storage for http cookies used by plugins
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINCOOKIESTORE_H
#define LL_LLPLUGINCOOKIESTORE_H
#include "lldate.h"
#include <map>
#include <string>
#include <iostream>
class LLPluginCookieStore
{
LOG_CLASS(LLPluginCookieStore);
public:
LLPluginCookieStore();
~LLPluginCookieStore();
// gets all cookies currently in storage -- use when initializing a plugin
std::string getAllCookies();
void writeAllCookies(std::ostream& s);
// gets only persistent cookies (i.e. not session cookies) -- use when writing cookies to a file
std::string getPersistentCookies();
void writePersistentCookies(std::ostream& s);
// gets cookies which are marked as "changed" -- use when sending periodic updates to plugins
std::string getChangedCookies(bool clear_changed = true);
void writeChangedCookies(std::ostream& s, bool clear_changed = true);
// (re)initializes internal data structures and bulk-sets cookies -- use when reading cookies from a file
void setAllCookies(const std::string &cookies, bool mark_changed = false);
void readAllCookies(std::istream& s, bool mark_changed = false);
// sets one or more cookies (without reinitializing anything) -- use when receiving cookies from a plugin
void setCookies(const std::string &cookies, bool mark_changed = true);
void readCookies(std::istream& s, bool mark_changed = true);
// sets one or more cookies (without reinitializing anything), supplying a hostname the cookies came from -- use when setting a cookie manually
void setCookiesFromHost(const std::string &cookies, const std::string &host, bool mark_changed = true);
// quote or unquote a string as per the definition of 'quoted-string' in rfc2616
static std::string quoteString(const std::string &s);
static std::string unquoteString(const std::string &s);
private:
void setOneCookie(const std::string &s, std::string::size_type cookie_start, std::string::size_type cookie_end, bool mark_changed, const std::string &host = LLStringUtil::null);
class Cookie
{
public:
static Cookie *createFromString(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos, const std::string &host = LLStringUtil::null);
// Construct a string from the cookie that uniquely represents it, to be used as a key in a std::map.
std::string getKey() const;
const std::string &getCookie() const { return mCookie; };
bool isSessionCookie() const { return mDate.isNull(); };
bool isDead() const { return mDead; };
void setDead(bool dead) { mDead = dead; };
bool isChanged() const { return mChanged; };
void setChanged(bool changed) { mChanged = changed; };
const LLDate &getDate() const { return mDate; };
private:
Cookie(const std::string &s, std::string::size_type cookie_start = 0, std::string::size_type cookie_end = std::string::npos);
bool parse(const std::string &host);
std::string::size_type findFieldEnd(std::string::size_type start = 0, std::string::size_type end = std::string::npos);
bool matchName(std::string::size_type start, std::string::size_type end, const char *name);
std::string mCookie; // The full cookie, in RFC 2109 string format
LLDate mDate; // The expiration date of the cookie. For session cookies, this will be a null date (mDate.isNull() is true).
// Start/end indices of various parts of the cookie string. Stored as indices into the string to save space and time.
std::string::size_type mNameStart, mNameEnd;
std::string::size_type mValueStart, mValueEnd;
std::string::size_type mDomainStart, mDomainEnd;
std::string::size_type mPathStart, mPathEnd;
bool mDead;
bool mChanged;
};
typedef std::map<std::string, Cookie*> cookie_map_t;
cookie_map_t mCookies;
bool mHasChangedCookies;
void clearCookies();
void removeCookie(const std::string &key);
};
#endif // LL_LLPLUGINCOOKIESTORE_H

9
indra/llplugin/llplugininstance.cpp Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llplugininstance.cpp
* @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"

10
indra/llplugin/llplugininstance.h Normal file → Executable file
View File

@@ -1,10 +1,10 @@
/**
* @file llplugininstance.h
* @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +12,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +28,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGININSTANCE_H

9
indra/llplugin/llpluginmessage.cpp Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginmessage.cpp
* @brief LLPluginMessage encapsulates the serialization/deserialization of messages passed to and from plugins.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"

10
indra/llplugin/llpluginmessage.h Normal file → Executable file
View File

@@ -1,10 +1,10 @@
/**
* @file llpluginmessage.h
* @brief LLPluginMessage encapsulates the serialization/deserialization of messages passed to and from plugins.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +12,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +28,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINMESSAGE_H

9
indra/llplugin/llpluginmessageclasses.h Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginmessageclasses.h
* @brief This file defines the versions of existing message classes for LLPluginMessage.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINMESSAGECLASSES_H

129
indra/llplugin/llpluginmessagepipe.cpp Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginmessagepipe.cpp
* @brief Classes that implement connections from the plugin system to pipes/pumps.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"
@@ -95,11 +98,14 @@ void LLPluginMessagePipeOwner::killMessagePipe(void)
}
}
LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket)
LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket):
mInputMutex(gAPRPoolp),
mOutputMutex(gAPRPoolp),
mOwner(owner),
mSocket(socket)
{
mOwner = owner;
mOwner->setMessagePipe(this);
mSocket = socket;
}
LLPluginMessagePipe::~LLPluginMessagePipe()
@@ -113,6 +119,7 @@ LLPluginMessagePipe::~LLPluginMessagePipe()
bool LLPluginMessagePipe::addMessage(const std::string &message)
{
// queue the message for later output
LLMutexLock lock(&mOutputMutex);
mOutput += message;
mOutput += MESSAGE_DELIMITER; // message separator
@@ -147,6 +154,18 @@ void LLPluginMessagePipe::setSocketTimeout(apr_interval_time_t timeout_usec)
}
bool LLPluginMessagePipe::pump(F64 timeout)
{
bool result = pumpOutput();
if(result)
{
result = pumpInput(timeout);
}
return result;
}
bool LLPluginMessagePipe::pumpOutput()
{
bool result = true;
@@ -155,6 +174,7 @@ bool LLPluginMessagePipe::pump(F64 timeout)
apr_status_t status;
apr_size_t size;
LLMutexLock lock(&mOutputMutex);
if(!mOutput.empty())
{
// write any outgoing messages
@@ -182,6 +202,17 @@ bool LLPluginMessagePipe::pump(F64 timeout)
// remove the written part from the buffer and try again later.
mOutput = mOutput.substr(size);
}
else if(APR_STATUS_IS_EOF(status))
{
// This is what we normally expect when a plugin exits.
llinfos << "Got EOF from plugin socket. " << llendl;
if(mOwner)
{
mOwner->socketError(status);
}
result = false;
}
else
{
// some other error
@@ -195,6 +226,19 @@ bool LLPluginMessagePipe::pump(F64 timeout)
result = false;
}
}
}
return result;
}
bool LLPluginMessagePipe::pumpInput(F64 timeout)
{
bool result = true;
if(mSocket)
{
apr_status_t status;
apr_size_t size;
// FIXME: For some reason, the apr timeout stuff isn't working properly on windows.
// Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead.
@@ -215,8 +259,16 @@ bool LLPluginMessagePipe::pump(F64 timeout)
char input_buf[1024];
apr_size_t request_size;
// Start out by reading one byte, so that any data received will wake us up.
request_size = 1;
if(timeout == 0.0f)
{
// If we have no timeout, start out with a full read.
request_size = sizeof(input_buf);
}
else
{
// Start out by reading one byte, so that any data received will wake us up.
request_size = 1;
}
// and use the timeout so we'll sleep if no data is available.
setSocketTimeout((apr_interval_time_t)(timeout * 1000000));
@@ -235,11 +287,14 @@ bool LLPluginMessagePipe::pump(F64 timeout)
// LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL;
if(size > 0)
{
LLMutexLock lock(&mInputMutex);
mInput.append(input_buf, size);
}
if(status == APR_SUCCESS)
{
// llinfos << "success, read " << size << llendl;
LL_DEBUGS("PluginSocket") << "success, read " << size << LL_ENDL;
if(size != request_size)
{
@@ -249,16 +304,28 @@ bool LLPluginMessagePipe::pump(F64 timeout)
}
else if(APR_STATUS_IS_TIMEUP(status))
{
// llinfos << "TIMEUP, read " << size << llendl;
LL_DEBUGS("PluginSocket") << "TIMEUP, read " << size << LL_ENDL;
// Timeout was hit. Since the initial read is 1 byte, this should never be a partial read.
break;
}
else if(APR_STATUS_IS_EAGAIN(status))
{
// llinfos << "EAGAIN, read " << size << llendl;
LL_DEBUGS("PluginSocket") << "EAGAIN, read " << size << LL_ENDL;
// We've been doing partial reads, and we're done now.
// Non-blocking read returned immediately.
break;
}
else if(APR_STATUS_IS_EOF(status))
{
// This is what we normally expect when a plugin exits.
LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL;
if(mOwner)
{
mOwner->socketError(status);
}
result = false;
break;
}
else
@@ -275,22 +342,18 @@ bool LLPluginMessagePipe::pump(F64 timeout)
break;
}
// Second and subsequent reads should not use the timeout
setSocketTimeout(0);
// and should try to fill the input buffer
request_size = sizeof(input_buf);
if(timeout != 0.0f)
{
// Second and subsequent reads should not use the timeout
setSocketTimeout(0);
// and should try to fill the input buffer
request_size = sizeof(input_buf);
}
}
processInput();
}
}
if(!result)
{
// If we got an error, we're done.
LL_INFOS("Plugin") << "Error from socket, cleaning up." << LL_ENDL;
delete this;
}
return result;
}
@@ -298,25 +361,27 @@ bool LLPluginMessagePipe::pump(F64 timeout)
void LLPluginMessagePipe::processInput(void)
{
// Look for input delimiter(s) in the input buffer.
int start = 0;
int delim;
while((delim = mInput.find(MESSAGE_DELIMITER, start)) != std::string::npos)
mInputMutex.lock();
while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos)
{
// Let the owner process this message
if (mOwner)
{
mOwner->receiveMessageRaw(mInput.substr(start, delim - start));
// Pull the message out of the input buffer before calling receiveMessageRaw.
// It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request)
// and this guarantees that the messages will get dequeued correctly.
std::string message(mInput, 0, delim);
mInput.erase(0, delim + 1);
mInputMutex.unlock();
mOwner->receiveMessageRaw(message);
mInputMutex.lock();
}
else
{
LL_WARNS("Plugin") << "!mOwner" << LL_ENDL;
}
start = delim + 1;
}
// Remove delivered messages from the input buffer.
if(start != 0)
mInput = mInput.substr(start);
mInputMutex.unlock();
}

18
indra/llplugin/llpluginmessagepipe.h Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginmessagepipe.h
* @brief Classes that implement connections from the plugin system to pipes/pumps.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,12 +29,15 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINMESSAGEPIPE_H
#define LL_LLPLUGINMESSAGEPIPE_H
#include "lliosocket.h"
#include "llthread.h"
class LLPluginMessagePipe;
@@ -50,7 +54,7 @@ public:
virtual apr_status_t socketError(apr_status_t error);
// called from LLPluginMessagePipe to manage the connection with LLPluginMessagePipeOwner -- do not use!
virtual void setMessagePipe(LLPluginMessagePipe *message_pipe) ;
virtual void setMessagePipe(LLPluginMessagePipe *message_pipe);
protected:
// returns false if writeMessageRaw() would drop the message
@@ -75,14 +79,18 @@ public:
void clearOwner(void);
bool pump(F64 timeout = 0.0f);
bool pumpOutput();
bool pumpInput(F64 timeout = 0.0f);
protected:
void processInput(void);
// used internally by pump()
void setSocketTimeout(apr_interval_time_t timeout_usec);
LLMutex mInputMutex;
std::string mInput;
LLMutex mOutputMutex;
std::string mOutput;
LLPluginMessagePipeOwner *mOwner;

107
indra/llplugin/llpluginprocesschild.cpp Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginprocesschild.cpp
* @brief LLPluginProcessChild handles the child side of the external-process plugin API.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"
@@ -42,10 +45,13 @@ static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f; // Each call to idle will
LLPluginProcessChild::LLPluginProcessChild()
{
mState = STATE_UNINITIALIZED;
mInstance = NULL;
mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
mSleepTime = PLUGIN_IDLE_SECONDS; // default: send idle messages at 100Hz
mCPUElapsed = 0.0f;
mBlockingRequest = false;
mBlockingResponseReceived = false;
}
LLPluginProcessChild::~LLPluginProcessChild()
@@ -58,7 +64,7 @@ LLPluginProcessChild::~LLPluginProcessChild()
// appears to fail and lock up which means that a given instance of the slplugin process never exits.
// This is bad, especially when users try to update their version of SL - it fails because the slplugin
// process as well as a bunch of plugin specific files are locked and cannot be overwritten.
exit(0);
exit( 0 );
//delete mInstance;
//mInstance = NULL;
}
@@ -81,9 +87,14 @@ void LLPluginProcessChild::idle(void)
bool idle_again;
do
{
if(mSocketError != APR_SUCCESS)
if(APR_STATUS_IS_EOF(mSocketError))
{
LL_INFOS("Plugin") << "message pipe is in error state, moving to STATE_ERROR"<< LL_ENDL;
// Plugin socket was closed. This covers both normal plugin termination and host crashes.
setState(STATE_ERROR);
}
else if(mSocketError != APR_SUCCESS)
{
LL_INFOS("Plugin") << "message pipe is in error state (" << mSocketError << "), moving to STATE_ERROR"<< LL_ENDL;
setState(STATE_ERROR);
}
@@ -153,7 +164,6 @@ void LLPluginProcessChild::idle(void)
{
setState(STATE_PLUGIN_INITIALIZING);
LLPluginMessage message("base", "init");
message.setValue("user_data_path", mUserDataPath);
sendMessageToPlugin(message);
}
break;
@@ -225,6 +235,7 @@ void LLPluginProcessChild::idle(void)
void LLPluginProcessChild::sleep(F64 seconds)
{
deliverQueuedMessages();
if(mMessagePipe)
{
mMessagePipe->pump(seconds);
@@ -237,6 +248,7 @@ void LLPluginProcessChild::sleep(F64 seconds)
void LLPluginProcessChild::pump(void)
{
deliverQueuedMessages();
if(mMessagePipe)
{
mMessagePipe->pump(0.0f);
@@ -278,14 +290,14 @@ void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message)
{
if (mInstance)
{
std::string buffer = message.generate();
LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL;
LLTimer elapsed;
mInstance->sendMessage(buffer);
mCPUElapsed += elapsed.getElapsedTimeF64();
std::string buffer = message.generate();
LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL;
LLTimer elapsed;
mInstance->sendMessage(buffer);
mCPUElapsed += elapsed.getElapsedTimeF64();
}
else
{
@@ -308,15 +320,32 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL;
// Decode this message
LLPluginMessage parsed;
parsed.parse(message);
if(mBlockingRequest)
{
// We're blocking the plugin waiting for a response.
if(parsed.hasValue("blocking_response"))
{
// This is the message we've been waiting for -- fall through and send it immediately.
mBlockingResponseReceived = true;
}
else
{
// Still waiting. Queue this message and don't process it yet.
mMessageQueue.push(message);
return;
}
}
bool passMessage = true;
// FIXME: how should we handle queueing here?
{
// Decode this message
LLPluginMessage parsed;
parsed.parse(message);
std::string message_class = parsed.getClass();
if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
{
@@ -326,7 +355,6 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
if(message_name == "load_plugin")
{
mPluginFile = parsed.getValue("file");
mUserDataPath = parsed.getValue("user_data_path");
}
else if(message_name == "shm_add")
{
@@ -425,7 +453,13 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
void LLPluginProcessChild::receivePluginMessage(const std::string &message)
{
LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL;
if(mBlockingRequest)
{
//
LL_ERRS("Plugin") << "Can't send a message while already waiting on a blocking request -- aborting!" << LL_ENDL;
}
// Incoming message from the plugin instance
bool passMessage = true;
@@ -436,6 +470,12 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)
// Decode this message
LLPluginMessage parsed;
parsed.parse(message);
if(parsed.hasValue("blocking_request"))
{
mBlockingRequest = true;
}
std::string message_class = parsed.getClass();
if(message_class == "base")
{
@@ -494,6 +534,19 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)
LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL;
writeMessageRaw(message);
}
while(mBlockingRequest)
{
// The plugin wants to block and wait for a response to this message.
sleep(mSleepTime); // this will pump the message pipe and process messages
if(mBlockingResponseReceived || mSocketError != APR_SUCCESS || (mMessagePipe == NULL))
{
// Response has been received, or we've hit an error state. Stop waiting.
mBlockingRequest = false;
mBlockingResponseReceived = false;
}
}
}
@@ -502,3 +555,15 @@ void LLPluginProcessChild::setState(EState state)
LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
mState = state;
};
void LLPluginProcessChild::deliverQueuedMessages()
{
if(!mBlockingRequest)
{
while(!mMessageQueue.empty())
{
receiveMessageRaw(mMessageQueue.front());
mMessageQueue.pop();
}
}
}

21
indra/llplugin/llpluginprocesschild.h Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginprocesschild.h
* @brief LLPluginProcessChild handles the child side of the external-process plugin API.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,11 +29,15 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINPROCESSCHILD_H
#define LL_LLPLUGINPROCESSCHILD_H
#include <queue> //imprudence
#include "llpluginmessage.h"
#include "llpluginmessagepipe.h"
#include "llplugininstance.h"
@@ -88,16 +93,15 @@ private:
STATE_ERROR, // generic bailout state
STATE_DONE // state machine will sit in this state after either error or normal termination.
};
EState mState;
void setState(EState state);
EState mState;
LLHost mLauncherHost;
LLSocket::ptr_t mSocket;
std::string mPluginFile;
std::string mUserDataPath;
LLPluginInstance *mInstance;
typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType;
@@ -106,6 +110,11 @@ private:
LLTimer mHeartbeat;
F64 mSleepTime;
F64 mCPUElapsed;
bool mBlockingRequest;
bool mBlockingResponseReceived;
std::queue<std::string> mMessageQueue;
void deliverQueuedMessages();
};

536
indra/llplugin/llpluginprocessparent.cpp Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginprocessparent.cpp
* @brief LLPluginProcessParent handles the parent side of the external-process plugin API.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"
@@ -44,25 +47,90 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
}
LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner)
bool LLPluginProcessParent::sUseReadThread = false;
apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
LLMutex *LLPluginProcessParent::sInstancesMutex;
std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances;
LLThread *LLPluginProcessParent::sReadThread = NULL;
class LLPluginProcessParentPollThread: public LLThread
{
public:
LLPluginProcessParentPollThread() :
LLThread("LLPluginProcessParentPollThread", gAPRPoolp)
{
}
protected:
// Inherited from LLThread
/*virtual*/ void run(void)
{
while(!isQuitting() && LLPluginProcessParent::getUseReadThread())
{
LLPluginProcessParent::poll(0.1f);
checkPause();
}
// Final poll to clean up the pollset, etc.
LLPluginProcessParent::poll(0.0f);
}
// Inherited from LLThread
/*virtual*/ bool runCondition(void)
{
return(LLPluginProcessParent::canPollThreadRun());
}
};
LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
mIncomingQueueMutex(gAPRPoolp)
{
if(!sInstancesMutex)
{
sInstancesMutex = new LLMutex(gAPRPoolp);
}
mOwner = owner;
mBoundPort = 0;
mState = STATE_UNINITIALIZED;
mSleepTime = 0.0;
mCPUUsage = 0.0;
mDisableTimeout = false;
mDebug = false;
mBlocked = false;
mPolledInput = false;
mPollFD.client_data = NULL;
mPluginLaunchTimeout = 60.0f;
mPluginLockupTimeout = 15.0f;
// Don't start the timer here -- start it when we actually launch the plugin process.
mHeartbeat.stop();
// Don't add to the global list until fully constructed.
{
LLMutexLock lock(sInstancesMutex);
sInstances.push_back(this);
}
}
LLPluginProcessParent::~LLPluginProcessParent()
{
LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
// Remove from the global list before beginning destruction.
{
// Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
LLMutexLock lock(sInstancesMutex);
{
LLMutexLock lock2(&mIncomingQueueMutex);
sInstances.remove(this);
}
}
// Destroy any remaining shared memory regions
sharedMemoryRegionsType::iterator iter;
while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end())
@@ -74,15 +142,17 @@ LLPluginProcessParent::~LLPluginProcessParent()
mSharedMemoryRegions.erase(iter);
}
// orphaning the process means it won't be killed when the LLProcessLauncher is destructed.
// This is what we want -- it should exit cleanly once it notices the sockets have been closed.
mProcess.orphan();
mProcess.kill();
killSockets();
}
void LLPluginProcessParent::killSockets(void)
{
killMessagePipe();
{
LLMutexLock lock(&mIncomingQueueMutex);
killMessagePipe();
}
mListenSocket.reset();
mSocket.reset();
}
@@ -95,14 +165,12 @@ void LLPluginProcessParent::errorState(void)
setState(STATE_ERROR);
}
void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path)
void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug)
{
mProcess.setExecutable(launcher_filename);
mPluginFile = plugin_filename;
mCPUUsage = 0.0f;
mDebug = debug;
mUserDataPath = user_data_path;
mDebug = debug;
setState(STATE_INITIALIZED);
}
@@ -158,21 +226,47 @@ void LLPluginProcessParent::idle(void)
do
{
// process queued messages
mIncomingQueueMutex.lock();
while(!mIncomingQueue.empty())
{
LLPluginMessage message = mIncomingQueue.front();
mIncomingQueue.pop();
mIncomingQueueMutex.unlock();
receiveMessage(message);
mIncomingQueueMutex.lock();
}
mIncomingQueueMutex.unlock();
// Give time to network processing
if(mMessagePipe)
{
if(!mMessagePipe->pump())
// Drain any queued outgoing messages
mMessagePipe->pumpOutput();
// Only do input processing here if this instance isn't in a pollset.
if(!mPolledInput)
{
// LL_WARNS("Plugin") << "Message pipe hit an error state" << LL_ENDL;
errorState();
mMessagePipe->pumpInput();
}
}
if((mSocketError != APR_SUCCESS) && (mState <= STATE_RUNNING))
if(mState <= STATE_RUNNING)
{
// The socket is in an error state -- the plugin is gone.
LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
errorState();
if(APR_STATUS_IS_EOF(mSocketError))
{
// Plugin socket was closed. This covers both normal plugin termination and plugin crashes.
errorState();
}
else if(mSocketError != APR_SUCCESS)
{
// The socket is in an error state -- the plugin is gone.
LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
errorState();
}
}
// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
@@ -314,6 +408,17 @@ void LLPluginProcessParent::idle(void)
mDebugger.addArgument("end tell");
mDebugger.launch();
#elif LL_LINUX
std::stringstream cmd;
mDebugger.setExecutable("/usr/bin/gnome-terminal");
mDebugger.addArgument("--geometry=165x24-0+0");
mDebugger.addArgument("-e");
cmd << "/usr/bin/gdb -n /proc/" << mProcess.getProcessID() << "/exe " << mProcess.getProcessID();
mDebugger.addArgument(cmd.str());
mDebugger.launch();
#endif
}
@@ -353,13 +458,12 @@ void LLPluginProcessParent::idle(void)
break;
case STATE_HELLO:
LL_DEBUGS("Plugin") << "received hello message" << llendl;
LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL;
// Send the message to load the plugin
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin");
message.setValue("file", mPluginFile);
message.setValue("user_data_path", mUserDataPath);
sendMessage(message);
}
@@ -388,7 +492,7 @@ void LLPluginProcessParent::idle(void)
}
else if(pluginLockedUp())
{
LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << llendl;
LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL;
errorState();
}
break;
@@ -410,8 +514,7 @@ void LLPluginProcessParent::idle(void)
break;
case STATE_CLEANUP:
// Don't do a kill here anymore -- closing the sockets is the new 'kill'.
mProcess.orphan();
mProcess.kill();
killSockets();
setState(STATE_DONE);
break;
@@ -479,23 +582,323 @@ void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send)
void LLPluginProcessParent::sendMessage(const LLPluginMessage &message)
{
if(message.hasValue("blocking_response"))
{
mBlocked = false;
// reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked.
mHeartbeat.setTimerExpirySec(mPluginLockupTimeout);
}
std::string buffer = message.generate();
LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL;
writeMessageRaw(buffer);
// Try to send message immediately.
if(mMessagePipe)
{
mMessagePipe->pumpOutput();
}
}
//virtual
void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe)
{
bool update_pollset = false;
if(mMessagePipe)
{
// Unsetting an existing message pipe -- remove from the pollset
mPollFD.client_data = NULL;
// pollset needs an update
update_pollset = true;
}
if(message_pipe != NULL)
{
// Set up the apr_pollfd_t
mPollFD.p = gAPRPoolp;
mPollFD.desc_type = APR_POLL_SOCKET;
mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP;
mPollFD.rtnevents = 0;
mPollFD.desc.s = mSocket->getSocket();
mPollFD.client_data = (void*)this;
// pollset needs an update
update_pollset = true;
}
mMessagePipe = message_pipe;
if(update_pollset)
{
dirtyPollSet();
}
}
//static
void LLPluginProcessParent::dirtyPollSet()
{
sPollsetNeedsRebuild = true;
if(sReadThread)
{
LL_DEBUGS("PluginPoll") << "unpausing read thread " << LL_ENDL;
sReadThread->unpause();
}
}
void LLPluginProcessParent::updatePollset()
{
if(!sInstancesMutex)
{
// No instances have been created yet. There's no work to do.
return;
}
LLMutexLock lock(sInstancesMutex);
if(sPollSet)
{
LL_DEBUGS("PluginPoll") << "destroying pollset " << sPollSet << LL_ENDL;
// delete the existing pollset.
apr_pollset_destroy(sPollSet);
sPollSet = NULL;
}
std::list<LLPluginProcessParent*>::iterator iter;
int count = 0;
// Count the number of instances that want to be in the pollset
for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
{
(*iter)->mPolledInput = false;
if((*iter)->mPollFD.client_data)
{
// This instance has a socket that needs to be polled.
++count;
}
}
if(sUseReadThread && sReadThread && !sReadThread->isQuitting())
{
if(!sPollSet && (count > 0))
{
#ifdef APR_POLLSET_NOCOPY
// The pollset doesn't exist yet. Create it now.
apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY);
if(status != APR_SUCCESS)
{
#endif // APR_POLLSET_NOCOPY
LL_WARNS("PluginPoll") << "Couldn't create pollset. Falling back to non-pollset mode." << LL_ENDL;
sPollSet = NULL;
#ifdef APR_POLLSET_NOCOPY
}
else
{
LL_DEBUGS("PluginPoll") << "created pollset " << sPollSet << LL_ENDL;
// Pollset was created, add all instances to it.
for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
{
if((*iter)->mPollFD.client_data)
{
status = apr_pollset_add(sPollSet, &((*iter)->mPollFD));
if(status == APR_SUCCESS)
{
(*iter)->mPolledInput = true;
}
else
{
LL_WARNS("PluginPoll") << "apr_pollset_add failed with status " << status << LL_ENDL;
}
}
}
}
#endif // APR_POLLSET_NOCOPY
}
}
}
void LLPluginProcessParent::setUseReadThread(bool use_read_thread)
{
if(sUseReadThread != use_read_thread)
{
sUseReadThread = use_read_thread;
if(sUseReadThread)
{
if(!sReadThread)
{
// start up the read thread
LL_INFOS("PluginPoll") << "creating read thread " << LL_ENDL;
// make sure the pollset gets rebuilt.
sPollsetNeedsRebuild = true;
sReadThread = new LLPluginProcessParentPollThread;
sReadThread->start();
}
}
else
{
if(sReadThread)
{
// shut down the read thread
LL_INFOS("PluginPoll") << "destroying read thread " << LL_ENDL;
delete sReadThread;
sReadThread = NULL;
}
}
}
}
void LLPluginProcessParent::poll(F64 timeout)
{
if(sPollsetNeedsRebuild || !sUseReadThread)
{
sPollsetNeedsRebuild = false;
updatePollset();
}
if(sPollSet)
{
apr_status_t status;
apr_int32_t count;
const apr_pollfd_t *descriptors;
status = apr_pollset_poll(sPollSet, (apr_interval_time_t)(timeout * 1000000), &count, &descriptors);
if(status == APR_SUCCESS)
{
// One or more of the descriptors signalled. Call them.
for(int i = 0; i < count; i++)
{
LLPluginProcessParent *self = (LLPluginProcessParent *)(descriptors[i].client_data);
// NOTE: the descriptor returned here is actually a COPY of the original (even though we create the pollset with APR_POLLSET_NOCOPY).
// This means that even if the parent has set its mPollFD.client_data to NULL, the old pointer may still there in this descriptor.
// It's even possible that the old pointer no longer points to a valid LLPluginProcessParent.
// This means that we can't safely dereference the 'self' pointer here without some extra steps...
if(self)
{
// Make sure this pointer is still in the instances list
bool valid = false;
{
LLMutexLock lock(sInstancesMutex);
for(std::list<LLPluginProcessParent*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
{
if(*iter == self)
{
// Lock the instance's mutex before unlocking the global mutex.
// This avoids a possible race condition where the instance gets deleted between this check and the servicePoll() call.
self->mIncomingQueueMutex.lock();
valid = true;
break;
}
}
}
if(valid)
{
// The instance is still valid.
// Pull incoming messages off the socket
self->servicePoll();
self->mIncomingQueueMutex.unlock();
}
else
{
LL_DEBUGS("PluginPoll") << "detected deleted instance " << self << LL_ENDL;
}
}
}
}
else if(APR_STATUS_IS_TIMEUP(status))
{
// timed out with no incoming data. Just return.
}
else if(status == EBADF)
{
// This happens when one of the file descriptors in the pollset is destroyed, which happens whenever a plugin's socket is closed.
// The pollset has been or will be recreated, so just return.
LL_DEBUGS("PluginPoll") << "apr_pollset_poll returned EBADF" << LL_ENDL;
}
else if(status != APR_SUCCESS)
{
LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL;
}
}
}
void LLPluginProcessParent::servicePoll()
{
bool result = true;
// poll signalled on this object's socket. Try to process incoming messages.
if(mMessagePipe)
{
result = mMessagePipe->pumpInput(0.0f);
}
if(!result)
{
// If we got a read error on input, remove this pipe from the pollset
apr_pollset_remove(sPollSet, &mPollFD);
// and tell the code not to re-add it
mPollFD.client_data = NULL;
}
}
void LLPluginProcessParent::receiveMessageRaw(const std::string &message)
{
LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL;
// FIXME: should this go into a queue instead?
LLPluginMessage parsed;
if(parsed.parse(message) != -1)
{
receiveMessage(parsed);
if(parsed.hasValue("blocking_request"))
{
mBlocked = true;
}
if(mPolledInput)
{
// This is being called on the polling thread -- only do minimal processing/queueing.
receiveMessageEarly(parsed);
}
else
{
// This is not being called on the polling thread -- do full message processing at this time.
receiveMessage(parsed);
}
}
}
void LLPluginProcessParent::receiveMessageEarly(const LLPluginMessage &message)
{
// NOTE: this function will be called from the polling thread. It will be called with mIncomingQueueMutex _already locked_.
bool handled = false;
std::string message_class = message.getClass();
if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
{
// no internal messages need to be handled early.
}
else
{
// Call out to the owner and see if they to reply
// TODO: Should this only happen when blocked?
if(mOwner != NULL)
{
handled = mOwner->receivePluginMessageEarly(message);
}
}
if(!handled)
{
// any message that wasn't handled early needs to be queued.
mIncomingQueue.push(message);
}
}
@@ -681,7 +1084,7 @@ std::string LLPluginProcessParent::getPluginVersion(void)
void LLPluginProcessParent::setState(EState state)
{
LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
LL_DEBUGS("Plugin") << "setting state to " << stateToString(state) << LL_ENDL;
mState = state;
};
@@ -689,18 +1092,15 @@ bool LLPluginProcessParent::pluginLockedUpOrQuit()
{
bool result = false;
if(!mDisableTimeout && !mDebug)
if(!mProcess.isRunning())
{
if(!mProcess.isRunning())
{
LL_WARNS("Plugin") << "child exited" << llendl;
result = true;
}
else if(pluginLockedUp())
{
LL_WARNS("Plugin") << "timeout" << llendl;
result = true;
}
LL_WARNS("Plugin") << "child exited" << LL_ENDL;
result = true;
}
else if(pluginLockedUp())
{
LL_WARNS("Plugin") << "timeout" << LL_ENDL;
result = true;
}
return result;
@@ -708,7 +1108,63 @@ bool LLPluginProcessParent::pluginLockedUpOrQuit()
bool LLPluginProcessParent::pluginLockedUp()
{
if(mDisableTimeout || mDebug || mBlocked)
{
// Never time out a plugin process in these cases.
return false;
}
// If the timer is running and has expired, the plugin has locked up.
return (mHeartbeat.getStarted() && mHeartbeat.hasExpired());
}
std::string LLPluginProcessParent::stateToString(EState state)
{
std::string eng = "unknown plugin state";
switch (state)
{
case STATE_UNINITIALIZED:
eng = "STATE_UNINITIALIZED";
break;
case STATE_INITIALIZED:
eng = "STATE_INITIALIZED - init() has been called";
break;
case STATE_LISTENING:
eng = "STATE_LISTENING - listening for incoming connection";
break;
case STATE_LAUNCHED:
eng = "STATE_LAUNCHED - process has been launched";
break;
case STATE_CONNECTED:
eng = "STATE_CONNECTED - process has connected";
break;
case STATE_HELLO:
eng = "STATE_HELLO - first message from the plugin process has been received";
break;
case STATE_LOADING:
eng = "STATE_LOADING - process has been asked to load the plugin";
break;
case STATE_RUNNING:
eng = "STATE_RUNNING - plugin running";
break;
case STATE_LAUNCH_FAILURE:
eng = "STATE_LAUNCH_FAILURE - failure before plugin loaded";
break;
case STATE_ERROR:
eng = "STATE_ERROR - generic bailout state";
break;
case STATE_CLEANUP:
eng = "STATE_CLEANUP - clean everything up";
break;
case STATE_EXITING:
eng = "STATE_EXITING - tried to kill process, waiting for it to exit";
break;
case STATE_DONE:
eng = "STATE_DONE - plugin done";
break;
default:
break;
}
return llformat("(%d) ", (S32)state) + eng;
}

49
indra/llplugin/llpluginprocessparent.h Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file llpluginprocessparent.h
* @brief LLPluginProcessParent handles the parent side of the external-process plugin API.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,11 +29,15 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINPROCESSPARENT_H
#define LL_LLPLUGINPROCESSPARENT_H
#include <queue> //imprudence
#include "llapr.h"
#include "llprocesslauncher.h"
#include "llpluginmessage.h"
@@ -40,12 +45,14 @@
#include "llpluginsharedmemory.h"
#include "lliosocket.h"
#include "llthread.h"
class LLPluginProcessParentOwner
{
public:
virtual ~LLPluginProcessParentOwner();
virtual void receivePluginMessage(const LLPluginMessage &message) = 0;
virtual bool receivePluginMessageEarly(const LLPluginMessage &message) {return false;};
// This will only be called when the plugin has died unexpectedly
virtual void pluginLaunchFailed() {};
virtual void pluginDied() {};
@@ -58,7 +65,10 @@ public:
LLPluginProcessParent(LLPluginProcessParentOwner *owner);
~LLPluginProcessParent();
void init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path);
void init(const std::string &launcher_filename,
const std::string &plugin_filename,
bool debug);
void idle(void);
// returns true if the plugin is on its way to steady state
@@ -70,6 +80,9 @@ public:
// returns true if the process has exited or we've had a fatal error
bool isDone(void);
// returns true if the process is currently waiting on a blocking request
bool isBlocked(void) { return mBlocked; };
void killSockets(void);
// Go to the proper error state
@@ -83,7 +96,9 @@ public:
void receiveMessage(const LLPluginMessage &message);
// Inherited from LLPluginMessagePipeOwner
void receiveMessageRaw(const std::string &message);
/*virtual*/ void receiveMessageRaw(const std::string &message);
/*virtual*/ void receiveMessageEarly(const LLPluginMessage &message);
/*virtual*/ void setMessagePipe(LLPluginMessagePipe *message_pipe) ;
// This adds a memory segment shared with the client, generating a name for the segment. The name generated is guaranteed to be unique on the host.
// The caller must call removeSharedMemory first (and wait until getSharedMemorySize returns 0 for the indicated name) before re-adding a segment with the same name.
@@ -106,7 +121,11 @@ public:
void setLockupTimeout(F32 timeout) { mPluginLockupTimeout = timeout; };
F64 getCPUUsage() { return mCPUUsage; };
static void poll(F64 timeout);
static bool canPollThreadRun() { return (sPollSet || sPollsetNeedsRebuild || sUseReadThread); };
static void setUseReadThread(bool use_read_thread);
static bool getUseReadThread() { return sUseReadThread; };
private:
enum EState
@@ -128,6 +147,7 @@ private:
};
EState mState;
void setState(EState state);
std::string stateToString(EState state);
bool pluginLockedUp();
bool pluginLockedUpOrQuit();
@@ -142,8 +162,6 @@ private:
std::string mPluginFile;
std::string mUserDataPath;
LLPluginProcessParentOwner *mOwner;
typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType;
@@ -158,12 +176,27 @@ private:
bool mDisableTimeout;
bool mDebug;
bool mBlocked;
bool mPolledInput;
LLProcessLauncher mDebugger;
F32 mPluginLaunchTimeout; // Somewhat longer timeout for initial launch.
F32 mPluginLockupTimeout; // If we don't receive a heartbeat in this many seconds, we declare the plugin locked up.
static bool sUseReadThread;
apr_pollfd_t mPollFD;
static apr_pollset_t *sPollSet;
static bool sPollsetNeedsRebuild;
static LLMutex *sInstancesMutex;
static std::list<LLPluginProcessParent*> sInstances;
static void dirtyPollSet();
static void updatePollset();
void servicePoll();
static LLThread *sReadThread;
LLMutex mIncomingQueueMutex;
std::queue<LLPluginMessage> mIncomingQueue;
};
#endif // LL_LLPLUGINPROCESSPARENT_H

11
indra/llplugin/llpluginsharedmemory.cpp Normal file → Executable file
View File

@@ -1,10 +1,11 @@
/**
* @file llpluginsharedmemory.cpp
* @brief LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API.
* LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"

10
indra/llplugin/llpluginsharedmemory.h Normal file → Executable file
View File

@@ -1,10 +1,10 @@
/**
* @file llpluginsharedmemory.h
* @brief LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +12,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +28,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LL_LLPLUGINSHAREDMEMORY_H

42
indra/llplugin/slplugin/CMakeLists.txt Normal file → Executable file
View File

@@ -16,6 +16,7 @@ include_directories(
if (DARWIN)
include(CMakeFindFrameworks)
find_library(CARBON_LIBRARY Carbon)
find_library(COCOA_LIBRARY Cocoa)
endif (DARWIN)
@@ -25,11 +26,33 @@ set(SLPlugin_SOURCE_FILES
slplugin.cpp
)
if (DARWIN)
list(APPEND SLPlugin_SOURCE_FILES
slplugin-objc.mm
)
list(APPEND SLPlugin_HEADER_FILES
slplugin-objc.h
)
endif (DARWIN)
set_source_files_properties(${SLPlugin_HEADER_FILES}
PROPERTIES HEADER_FILE_ONLY TRUE)
if (SLPlugin_HEADER_FILES)
list(APPEND SLPlugin_SOURCE_FILES ${SLPlugin_HEADER_FILES})
endif (SLPlugin_HEADER_FILES)
add_executable(SLPlugin
WIN32
MACOSX_BUNDLE
${SLPlugin_SOURCE_FILES}
)
set_target_properties(SLPlugin
PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist
)
target_link_libraries(SLPlugin
${LLPLUGIN_LIBRARIES}
${LLMESSAGE_LIBRARIES}
@@ -44,15 +67,16 @@ add_dependencies(SLPlugin
)
if (DARWIN)
# Mac version needs to link against carbon, and also needs an embedded plist (to set LSBackgroundOnly)
target_link_libraries(SLPlugin ${CARBON_LIBRARY})
set_target_properties(
SLPlugin
PROPERTIES
LINK_FLAGS "-Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist"
# Mac version needs to link against Carbon
target_link_libraries(SLPlugin ${CARBON_LIBRARY} ${COCOA_LIBRARY})
# Make sure the app bundle has a Resources directory (it will get populated by viewer-manifest.py later)
add_custom_command(
TARGET SLPlugin POST_BUILD
COMMAND mkdir
ARGS
-p
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/SLPlugin.app/Contents/Resources
)
endif (DARWIN)
if (LINUX)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt")
endif (LINUX)
#ll_deploy_sharedlibs_command(SLPlugin)

View File

@@ -0,0 +1,42 @@
/**
* @file slplugin-objc.h
* @brief Header file for slplugin-objc.mm.
*
* @cond
*
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
*
* @endcond
*/
/* Defined in slplugin-objc.mm: */
void setupCocoa();
void createAutoReleasePool();
void deleteAutoReleasePool();

View File

@@ -0,0 +1,89 @@
/**
* @file slplugin-objc.mm
* @brief Objective-C++ file for use with the loader shell, so we can use a couple of Cocoa APIs.
*
* @cond
*
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
*
* @endcond
*/
#include <AppKit/AppKit.h>
#include "slplugin-objc.h"
void setupCocoa()
{
static bool inited = false;
if(!inited)
{
createAutoReleasePool();
// The following prevents the Cocoa command line parser from trying to open 'unknown' arguements as documents.
// ie. running './secondlife -set Language fr' would cause a pop-up saying can't open document 'fr'
// when init'ing the Cocoa App window.
[[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
// This is a bit of voodoo taken from the Apple sample code "CarbonCocoa_PictureCursor":
// http://developer.apple.com/samplecode/CarbonCocoa_PictureCursor/index.html
// Needed for Carbon based applications which call into Cocoa
NSApplicationLoad();
// Must first call [[[NSWindow alloc] init] release] to get the NSWindow machinery set up so that NSCursor can use a window to cache the cursor image
[[[NSWindow alloc] init] release];
deleteAutoReleasePool();
inited = true;
}
}
static NSAutoreleasePool *sPool = NULL;
void createAutoReleasePool()
{
if(!sPool)
{
sPool = [[NSAutoreleasePool alloc] init];
}
}
void deleteAutoReleasePool()
{
if(sPool)
{
[sPool release];
sPool = NULL;
}
}

170
indra/llplugin/slplugin/slplugin.cpp Normal file → Executable file
View File

@@ -1,10 +1,12 @@
/**
/**
* @file slplugin.cpp
* @brief Loader shell for plugins, intended to be launched by the plugin host application, which directly loads a plugin dynamic library.
*
* @cond
*
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +14,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +30,9 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
*
* @endcond
*/
@@ -41,6 +46,7 @@
#if LL_DARWIN
#include <Carbon/Carbon.h>
#include "slplugin-objc.h"
#endif
#if LL_DARWIN || LL_LINUX
@@ -48,16 +54,17 @@
#endif
/*
On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly flag in the Info.plist.
On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly or LSUIElement flag in the Info.plist.
Normally non-bundled binaries don't have an info.plist file, but it's possible to embed one in the binary by adding this to the linker flags:
-sectcreate __TEXT __info_plist /path/to/slplugin_info.plist
which means adding this to the gcc flags:
-Wl,-sectcreate,__TEXT,__info_plist,/path/to/slplugin_info.plist
Now that SLPlugin is a bundled app on the Mac, this is no longer necessary (it can just use a regular Info.plist file), but I'm leaving this comment in for posterity.
*/
#if LL_DARWIN || LL_LINUX
@@ -68,7 +75,7 @@ static void crash_handler(int sig)
// TODO: add our own crash reporting
_exit(1);
}
#endif
#endif
#if LL_WINDOWS
#include <windows.h>
@@ -81,7 +88,7 @@ LONG WINAPI myWin32ExceptionHandler( struct _EXCEPTION_POINTERS* exception_infop
//std::cerr << "intercepted an unhandled exception and will exit immediately." << std::endl;
// TODO: replace exception handler before we exit?
return EXCEPTION_EXECUTE_HANDLER;
return EXCEPTION_EXECUTE_HANDLER;
}
// Taken from : http://blog.kalmbachnet.de/?postid=75
@@ -153,7 +160,7 @@ bool checkExceptionHandler()
if (prev_filter == NULL)
{
ok = FALSE;
if (myWin32ExceptionHandler == NULL)
if (NULL == myWin32ExceptionHandler)
{
LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL;
}
@@ -167,7 +174,7 @@ bool checkExceptionHandler()
}
#endif
// If this application on Windows platform is a console application, a console is always
// If this application on Windows platform is a console application, a console is always
// created which is bad. Making it a Windows "application" via CMake settings but not
// adding any code to explicitly create windows does the right thing.
#if LL_WINDOWS
@@ -178,7 +185,7 @@ int main(int argc, char **argv)
{
ll_init_apr();
// Set up llerror logging
// Set up llerror logging
{
LLError::initForApplication(".");
LLError::setDefaultLevel(LLError::LEVEL_INFO);
@@ -191,25 +198,23 @@ int main(int argc, char **argv)
{
LL_ERRS("slplugin") << "usage: " << "SLPlugin" << " launcher_port" << LL_ENDL;
};
U32 port = 0;
if(!LLStringUtil::convertToU32(lpCmdLine, port))
{
LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL;
};
// Insert our exception handler into the system so this plugin doesn't
// Insert our exception handler into the system so this plugin doesn't
// display a crash message if something bad happens. The host app will
// see the missing heartbeat and log appropriately.
initExceptionHandler();
#elif LL_DARWIN || LL_LINUX
setpriority(PRIO_PROCESS, getpid(), 19);
if(argc < 2)
{
LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL;
}
U32 port = 0;
if(!LLStringUtil::convertToU32(argv[1], port))
{
@@ -227,23 +232,50 @@ int main(int argc, char **argv)
signal(SIGSYS, &crash_handler); // non-existent system call invoked
#endif
#if LL_DARWIN
setupCocoa();
createAutoReleasePool();
#endif
LLPluginProcessChild *plugin = new LLPluginProcessChild();
plugin->init(port);
#if LL_DARWIN
deleteAutoReleasePool();
#endif
LLTimer timer;
timer.start();
#if LL_WINDOWS
checkExceptionHandler();
#endif
#if LL_DARWIN
// If the plugin opens a new window (such as the Flash plugin's fullscreen player), we may need to bring this plugin process to the foreground.
// Use this to track the current frontmost window and bring this process to the front if it changes.
WindowRef front_window = NULL;
WindowGroupRef layer_group = NULL;
int window_hack_state = 0;
CreateWindowGroup(kWindowGroupAttrFixedLevel, &layer_group);
if(layer_group)
{
// Start out with a window layer that's way out in front (fixes the problem with the menubar not getting hidden on first switch to fullscreen youtube)
SetWindowGroupName(layer_group, CFSTR("SLPlugin Layer"));
SetWindowGroupLevel(layer_group, kCGOverlayWindowLevel);
}
#endif
#if LL_DARWIN
EventTargetRef event_target = GetEventDispatcherTarget();
#endif
while(!plugin->isDone())
{
timer.reset();
#if LL_DARWIN
createAutoReleasePool();
#endif
timer.reset();
plugin->idle();
#if LL_DARWIN
{
@@ -254,11 +286,85 @@ int main(int argc, char **argv)
SendEventToEventTarget (event, event_target);
ReleaseEvent(event);
}
// Check for a change in this process's frontmost window.
if(FrontWindow() != front_window)
{
ProcessSerialNumber self = { 0, kCurrentProcess };
ProcessSerialNumber parent = { 0, kNoProcess };
ProcessSerialNumber front = { 0, kNoProcess };
Boolean this_is_front_process = false;
Boolean parent_is_front_process = false;
{
// Get this process's parent
ProcessInfoRec info;
info.processInfoLength = sizeof(ProcessInfoRec);
info.processName = NULL;
info.processAppSpec = NULL;
if(GetProcessInformation( &self, &info ) == noErr)
{
parent = info.processLauncher;
}
// and figure out whether this process or its parent are currently frontmost
if(GetFrontProcess(&front) == noErr)
{
(void) SameProcess(&self, &front, &this_is_front_process);
(void) SameProcess(&parent, &front, &parent_is_front_process);
}
}
if((FrontWindow() != NULL) && (front_window == NULL))
{
// Opening the first window
if(window_hack_state == 0)
{
// Next time through the event loop, lower the window group layer
window_hack_state = 1;
}
if(layer_group)
{
SetWindowGroup(FrontWindow(), layer_group);
}
if(parent_is_front_process)
{
// Bring this process's windows to the front.
(void) SetFrontProcess( &self );
}
ActivateWindow(FrontWindow(), true);
}
else if((FrontWindow() == NULL) && (front_window != NULL))
{
// Closing the last window
if(this_is_front_process)
{
// Try to bring this process's parent to the front
(void) SetFrontProcess(&parent);
}
}
else if(window_hack_state == 1)
{
if(layer_group)
{
// Set the window group level back to something less extreme
SetWindowGroupLevel(layer_group, kCGNormalWindowLevel);
}
window_hack_state = 2;
}
front_window = FrontWindow();
}
}
#endif
F64 elapsed = timer.getElapsedTimeF64();
F64 remaining = plugin->getSleepTime() - elapsed;
if(remaining <= 0.0f)
{
// We've already used our full allotment.
@@ -271,26 +377,30 @@ int main(int argc, char **argv)
{
// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, sleeping for " << remaining * 1000.0f << " ms" << LL_ENDL;
// timer.reset();
// timer.reset();
// This also services the network as needed.
plugin->sleep(remaining);
// LL_INFOS("slplugin") << "slept for "<< timer.getElapsedTimeF64() * 1000.0f << " ms" << LL_ENDL;
}
#if LL_WINDOWS
// More agressive checking of interfering exception handlers.
// Doesn't appear to be required so far - even for plugins
// that do crash with a single call to the intercept
// Doesn't appear to be required so far - even for plugins
// that do crash with a single call to the intercept
// exception handler such as QuickTime.
//checkExceptionHandler();
#endif
#if LL_DARWIN
deleteAutoReleasePool();
#endif
}
delete plugin;
ll_cleanup_apr();
ll_cleanup_apr();
return 0;
}

4
indra/llplugin/slplugin/slplugin_info.plist Normal file → Executable file
View File

@@ -6,7 +6,7 @@
<string>English</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>LSBackgroundOnly</key>
<true/>
<key>LSUIElement</key>
<string>1</string>
</dict>
</plist>

8
indra/media_plugins/CMakeLists.txt Normal file → Executable file
View File

@@ -4,10 +4,12 @@ add_subdirectory(base)
add_subdirectory(webkit)
add_subdirectory(gstreamer010)
if (LINUX OR DARWIN)
add_subdirectory(gstreamer010)
endif (LINUX OR DARWIN)
if (WINDOWS OR DARWIN)
if (WINDOWS)
add_subdirectory(quicktime)
endif (WINDOWS OR DARWIN)
endif (WINDOWS)
add_subdirectory(example)

View File

@@ -25,13 +25,13 @@ include_directories(
### media_plugin_base
if(WORD_SIZE EQUAL 64)
if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4)
if(WINDOWS)
add_definitions(/FIXED:NO)
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
add_definitions(-fPIC)
endif(WINDOWS)
endif (WORD_SIZE EQUAL 64)
endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4)
set(media_plugin_base_SOURCE_FILES
media_plugin_base.cpp
@@ -47,7 +47,3 @@ add_library(media_plugin_base
${media_plugin_base_SOURCE_FILES}
)
add_dependencies(media_plugin_base
prepare
)

9
indra/media_plugins/base/media_plugin_base.cpp Normal file → Executable file
View File

@@ -4,9 +4,10 @@
*
* All plugins should be a subclass of MediaPluginBase.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -14,13 +15,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -30,6 +31,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"

0
indra/media_plugins/base/media_plugin_base.exp Normal file → Executable file
View File

9
indra/media_plugins/base/media_plugin_base.h Normal file → Executable file
View File

@@ -2,9 +2,10 @@
* @file media_plugin_base.h
* @brief Media plugin base class for LLMedia API plugin system
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"

View File

@@ -14,7 +14,7 @@ include(PluginAPI)
include(MediaPluginBase)
include(FindOpenGL)
include(ExamplePlugin)
#include(ExamplePlugin)
include_directories(
${LLPLUGIN_INCLUDE_DIRS}
@@ -29,13 +29,13 @@ include_directories(
### media_plugin_example
if(WORD_SIZE EQUAL 64)
if(NOT CMAKE_SIZEOF_VOID_P MATCHES 4)
if(WINDOWS)
add_definitions(/FIXED:NO)
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
add_definitions(-fPIC)
endif(WINDOWS)
endif (WORD_SIZE EQUAL 64)
endif (NOT CMAKE_SIZEOF_VOID_P MATCHES 4)
set(media_plugin_example_SOURCE_FILES
media_plugin_example.cpp

44
indra/media_plugins/example/media_plugin_example.cpp Normal file → Executable file
View File

@@ -2,10 +2,11 @@
* @file media_plugin_example.cpp
* @brief Example plugin for LLMedia API plugin system
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2009, Linden Research, Inc.
*
*
* Copyright (c) 2008-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
@@ -13,20 +14,23 @@
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at http://secondlife.com/developers/opensource/flossexception
*
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"
@@ -117,17 +121,6 @@ void MediaPluginExample::receiveMessage( const char* message_string )
std::string plugin_version = "Example media plugin, Example Version 1.0.0.0";
message.setValue( "plugin_version", plugin_version );
sendMessage( message );
// Plugin gets to decide the texture parameters to use.
message.setMessage( LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params" );
message.setValueS32( "default_width", mWidth );
message.setValueS32( "default_height", mHeight );
message.setValueS32( "depth", mDepth );
message.setValueU32( "internalformat", GL_RGBA );
message.setValueU32( "format", GL_RGBA );
message.setValueU32( "type", GL_UNSIGNED_BYTE );
message.setValueBoolean( "coords_opengl", false );
sendMessage( message );
}
else
if ( message_name == "idle" )
@@ -189,7 +182,20 @@ void MediaPluginExample::receiveMessage( const char* message_string )
else
if ( message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA )
{
if ( message_name == "size_change" )
if ( message_name == "init" )
{
// Plugin gets to decide the texture parameters to use.
LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params" );
message.setValueS32( "default_width", mWidth );
message.setValueS32( "default_height", mHeight );
message.setValueS32( "depth", mDepth );
message.setValueU32( "internalformat", GL_RGBA );
message.setValueU32( "format", GL_RGBA );
message.setValueU32( "type", GL_UNSIGNED_BYTE );
message.setValueBoolean( "coords_opengl", false );
sendMessage( message );
}
else if ( message_name == "size_change" )
{
std::string name = message_in.getValue( "name" );
S32 width = message_in.getValueS32( "width" );

View File

@@ -32,16 +32,14 @@ include_directories(
set(media_plugin_gstreamer010_SOURCE_FILES
media_plugin_gstreamer010.cpp
llmediaimplgstreamer_syms.cpp
llmediaimplgstreamervidplug.cpp
)
set(media_plugin_gstreamer010_HEADER_FILES
llmediaimplgstreamervidplug.h
llmediaimplgstreamer_syms.h
llmediaimplgstreamertriviallogging.h
)
add_library(media_plugin_gstreamer010
SHARED
${media_plugin_gstreamer010_SOURCE_FILES}

View File

@@ -3,9 +3,10 @@
* @author Tofu Linden
* @brief implementation that supports media playback via GStreamer.
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Copyright (c) 2007-2009, Linden Research, Inc.
* Copyright (c) 2007-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -13,13 +14,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -29,6 +30,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
// header guard

View File

@@ -1,171 +0,0 @@
/**
* @file llmediaimplgstreamer_syms.cpp
* @brief dynamic GStreamer symbol-grabbing code
*
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Copyright (c) 2007-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#if LL_GSTREAMER010_ENABLED
#include <string>
extern "C" {
#include <gst/gst.h>
#include "apr_pools.h"
#include "apr_dso.h"
}
#include "llmediaimplgstreamertriviallogging.h"
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL
#include "llmediaimplgstreamer_syms_raw.inc"
#include "llmediaimplgstreamer_syms_rawv.inc"
#undef LL_GST_SYM
// a couple of stubs for disgusting reasons
GstDebugCategory*
ll_gst_debug_category_new(gchar *name, guint color, gchar *description)
{
static GstDebugCategory dummy;
return &dummy;
}
void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname)
{
}
static bool sSymsGrabbed = false;
static apr_pool_t *sSymGSTDSOMemoryPool = NULL;
static apr_dso_handle_t *sSymGSTDSOHandleG = NULL;
static apr_dso_handle_t *sSymGSTDSOHandleV = NULL;
bool grab_gst_syms(std::string gst_dso_name,
std::string gst_dso_name_vid)
{
if (sSymsGrabbed)
{
// already have grabbed good syms
return TRUE;
}
bool sym_error = false;
bool rtn = false;
apr_status_t rv;
apr_dso_handle_t *sSymGSTDSOHandle = NULL;
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0)
//attempt to load the shared libraries
apr_pool_create(&sSymGSTDSOMemoryPool, NULL);
if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle,
gst_dso_name.c_str(),
sSymGSTDSOMemoryPool) ))
{
INFOMSG("Found DSO: %s", gst_dso_name.c_str());
#include "llmediaimplgstreamer_syms_raw.inc"
if ( sSymGSTDSOHandle )
{
sSymGSTDSOHandleG = sSymGSTDSOHandle;
sSymGSTDSOHandle = NULL;
}
if ( APR_SUCCESS ==
(rv = apr_dso_load(&sSymGSTDSOHandle,
gst_dso_name_vid.c_str(),
sSymGSTDSOMemoryPool) ))
{
INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str());
#include "llmediaimplgstreamer_syms_rawv.inc"
rtn = !sym_error;
}
else
{
INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str());
rtn = false; // failure
}
}
else
{
INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str());
rtn = false; // failure
}
if (sym_error)
{
WARNMSG("Failed to find necessary symbols in GStreamer libraries.");
}
if ( sSymGSTDSOHandle )
{
sSymGSTDSOHandleV = sSymGSTDSOHandle;
sSymGSTDSOHandle = NULL;
}
#undef LL_GST_SYM
sSymsGrabbed = !!rtn;
return rtn;
}
void ungrab_gst_syms()
{
// should be safe to call regardless of whether we've
// actually grabbed syms.
if ( sSymGSTDSOHandleG )
{
apr_dso_unload(sSymGSTDSOHandleG);
sSymGSTDSOHandleG = NULL;
}
if ( sSymGSTDSOHandleV )
{
apr_dso_unload(sSymGSTDSOHandleV);
sSymGSTDSOHandleV = NULL;
}
if ( sSymGSTDSOMemoryPool )
{
apr_pool_destroy(sSymGSTDSOMemoryPool);
sSymGSTDSOMemoryPool = NULL;
}
// NULL-out all of the symbols we'd grabbed
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0)
#include "llmediaimplgstreamer_syms_raw.inc"
#include "llmediaimplgstreamer_syms_rawv.inc"
#undef LL_GST_SYM
sSymsGrabbed = false;
}
#endif // LL_GSTREAMER010_ENABLED

View File

@@ -1,78 +0,0 @@
/**
* @file llmediaimplgstreamer_syms.h
* @brief dynamic GStreamer symbol-grabbing code
*
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Copyright (c) 2007-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#if LL_GSTREAMER010_ENABLED
extern "C" {
#include <gst/gst.h>
}
bool grab_gst_syms(std::string gst_dso_name,
std::string gst_dso_name_vid);
void ungrab_gst_syms();
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__)
#include "llmediaimplgstreamer_syms_raw.inc"
#include "llmediaimplgstreamer_syms_rawv.inc"
#undef LL_GST_SYM
// regrettable hacks to give us better runtime compatibility with older systems
#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0)
#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0)
// regrettable hacks because GStreamer was not designed for runtime loading
#undef GST_TYPE_MESSAGE
#define GST_TYPE_MESSAGE (llgst_message_get_type())
#undef GST_TYPE_OBJECT
#define GST_TYPE_OBJECT (llgst_object_get_type())
#undef GST_TYPE_PIPELINE
#define GST_TYPE_PIPELINE (llgst_pipeline_get_type())
#undef GST_TYPE_ELEMENT
#define GST_TYPE_ELEMENT (llgst_element_get_type())
#undef GST_TYPE_VIDEO_SINK
#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type())
// more regrettable hacks to stub-out these .h-exposed GStreamer internals
void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname);
#undef _gst_debug_register_funcptr
#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr
GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description);
#undef _gst_debug_category_new
#define _gst_debug_category_new ll_gst_debug_category_new
#undef __gst_debug_enabled
#define __gst_debug_enabled (0)
// more hacks
#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M)))
#endif // LL_GSTREAMER010_ENABLED

View File

@@ -1,51 +0,0 @@
// required symbols to grab
LL_GST_SYM(true, gst_pad_peer_accept_caps, gboolean, GstPad *pad, GstCaps *caps);
LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void);
LL_GST_SYM(true, gst_buffer_set_caps, void, GstBuffer*, GstCaps *);
LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*);
LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err);
LL_GST_SYM(true, gst_message_get_type, GType, void);
LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type);
LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug);
LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug);
LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending);
LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state);
LL_GST_SYM(true, gst_object_unref, void, gpointer object);
LL_GST_SYM(true, gst_object_get_type, GType, void);
LL_GST_SYM(true, gst_pipeline_get_type, GType, void);
LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline);
LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data);
LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name);
LL_GST_SYM(true, gst_element_get_type, GType, void);
LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template);
LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp);
LL_GST_SYM(true, gst_element_class_set_details, void, GstElementClass *klass, const GstElementDetails *details);
LL_GST_SYM(true, gst_caps_unref, void, GstCaps* caps);
LL_GST_SYM(true, gst_caps_ref, GstCaps *, GstCaps* caps);
//LL_GST_SYM(true, gst_caps_is_empty, gboolean, const GstCaps *caps);
LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string);
LL_GST_SYM(true, gst_caps_replace, void, GstCaps **caps, GstCaps *newcaps);
LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index);
LL_GST_SYM(true, gst_caps_copy, GstCaps *, const GstCaps * caps);
//LL_GST_SYM(true, gst_caps_intersect, GstCaps *, const GstCaps *caps1, const GstCaps *caps2);
LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type);
LL_GST_SYM(true, _gst_plugin_register_static, void, GstPluginDesc *desc);
LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value);
LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname);
LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value);
LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value);
LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure);
LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64);
// optional symbols to grab
LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled);
LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled);
LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent);
LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug);
LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur);
LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano);
// GStreamer 'internal' symbols which may not be visible in some runtimes but are still used in expanded GStreamer header macros - yuck! We'll substitute our own stubs for these.
//LL_GST_SYM(true, _gst_debug_register_funcptr, void, GstDebugFuncPtr func, gchar* ptrname);
//LL_GST_SYM(true, _gst_debug_category_new, GstDebugCategory *, gchar *name, guint color, gchar *description);

View File

@@ -1,5 +0,0 @@
// required symbols to grab
LL_GST_SYM(true, gst_video_sink_get_type, GType, void);
// optional symbols to grab

View File

@@ -2,9 +2,10 @@
* @file llmediaimplgstreamertriviallogging.h
* @brief minimal logging utilities.
*
* @cond
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2009, Linden Research, Inc.
* Copyright (c) 2009-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__

View File

@@ -1,10 +1,11 @@
/**
* @file llmediaimplgstreamervidplug.cpp
* @file llmediaimplgstreamervidplug.h
* @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Copyright (c) 2007-2009, Linden Research, Inc.
* Copyright (c) 2007-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#if LL_GSTREAMER010_ENABLED
@@ -38,15 +41,29 @@
#include <gst/video/video.h>
#include <gst/video/gstvideosink.h>
#include "llmediaimplgstreamer_syms.h"
#include "llmediaimplgstreamertriviallogging.h"
// #include "llthread.h"
#include "llmediaimplgstreamervidplug.h"
GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug);
#define GST_CAT_DEFAULT gst_slvideo_debug
/* Filter signals and args *//*
enum
{
*//* FILL ME *//*
LAST_SIGNAL
};
enum
{
ARG_0
};
#define SLV_SIZECAPS ", width=(int){1,2,4,8,16,32,64,128,256,512,1024}, height=(int){1,2,4,8,16,32,64,128,256,512,1024} "
#define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS ";" GST_VIDEO_CAPS_BGRx SLV_SIZECAPS
*/
#define SLV_SIZECAPS ", width=(int)[1,2048], height=(int)[1,2048] "
#define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS
@@ -78,9 +95,9 @@ gst_slvideo_base_init (gpointer gclass)
};
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
llgst_element_class_add_pad_template (element_class,
llgst_static_pad_template_get (&sink_factory));
llgst_element_class_set_details (element_class, &element_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details (element_class, &element_details);
}
@@ -91,7 +108,7 @@ gst_slvideo_finalize (GObject * object)
slvideo = GST_SLVIDEO (object);
if (slvideo->caps)
{
llgst_caps_unref(slvideo->caps);
gst_caps_unref(slvideo->caps);
}
G_OBJECT_CLASS(parent_class)->finalize (object);
@@ -102,7 +119,7 @@ static GstFlowReturn
gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf)
{
GstSLVideo *slvideo;
llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
slvideo = GST_SLVIDEO(bsink);
@@ -194,7 +211,7 @@ gst_slvideo_get_caps (GstBaseSink * bsink)
GstSLVideo *slvideo;
slvideo = GST_SLVIDEO(bsink);
return llgst_caps_ref (slvideo->caps);
return gst_caps_ref (slvideo->caps);
}
@@ -204,21 +221,32 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
GstSLVideo *filter;
GstStructure *structure;
// GstCaps *intersection;
GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
filter = GST_SLVIDEO(bsink);
int width, height;
/*
intersection = gst_caps_intersect (filter->caps, caps);
if (gst_caps_is_empty (intersection))
{
// no overlap between our caps and requested caps
return FALSE;
}
gst_caps_unref(intersection);
*/
int width = 0;
int height = 0;
gboolean ret;
const GValue *fps;
const GValue *par;
structure = llgst_caps_get_structure (caps, 0);
ret = llgst_structure_get_int (structure, "width", &width);
ret = ret && llgst_structure_get_int (structure, "height", &height);
fps = llgst_structure_get_value (structure, "framerate");
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "width", &width);
ret = ret && gst_structure_get_int (structure, "height", &height);
fps = gst_structure_get_value (structure, "framerate");
ret = ret && (fps != NULL);
par = llgst_structure_get_value (structure, "pixel-aspect-ratio");
par = gst_structure_get_value (structure, "pixel-aspect-ratio");
if (!ret)
return FALSE;
@@ -228,34 +256,35 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps)
filter->width = width;
filter->height = height;
filter->fps_n = llgst_value_get_fraction_numerator(fps);
filter->fps_d = llgst_value_get_fraction_denominator(fps);
filter->fps_n = gst_value_get_fraction_numerator(fps);
filter->fps_d = gst_value_get_fraction_denominator(fps);
if (par)
{
filter->par_n = llgst_value_get_fraction_numerator(par);
filter->par_d = llgst_value_get_fraction_denominator(par);
filter->par_n = gst_value_get_fraction_numerator(par);
filter->par_d = gst_value_get_fraction_denominator(par);
}
else
{
filter->par_n = 1;
filter->par_d = 1;
}
GST_VIDEO_SINK_WIDTH(filter) = width;
GST_VIDEO_SINK_HEIGHT(filter) = height;
// crufty lump - we *always* accept *only* RGBX now.
/*
filter->format = SLV_PF_UNKNOWN;
if (0 == strcmp(llgst_structure_get_name(structure),
if (0 == strcmp(gst_structure_get_name(structure),
"video/x-raw-rgb"))
{
int red_mask;
int green_mask;
int blue_mask;
llgst_structure_get_int(structure, "red_mask", &red_mask);
llgst_structure_get_int(structure, "green_mask", &green_mask);
llgst_structure_get_int(structure, "blue_mask", &blue_mask);
gst_structure_get_int(structure, "red_mask", &red_mask);
gst_structure_get_int(structure, "green_mask", &green_mask);
gst_structure_get_int(structure, "blue_mask", &blue_mask);
if ((unsigned int)red_mask == 0xFF000000 &&
(unsigned int)green_mask == 0x00FF0000 &&
(unsigned int)blue_mask == 0x0000FF00)
@@ -269,12 +298,13 @@ gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps)
filter->format = SLV_PF_BGRX;
//fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n");
}
}*/
}*/
filter->format = SLV_PF_RGBX;
GST_OBJECT_UNLOCK(filter);
return TRUE;
}
@@ -321,15 +351,15 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
// we can ignore these and reverse-negotiate our preferred dimensions with
// the peer if we like - we need to do this to obey dynamic resize requests
// flowing in from the app.
structure = llgst_caps_get_structure (caps, 0);
if (!llgst_structure_get_int(structure, "width", &width) ||
!llgst_structure_get_int(structure, "height", &height))
structure = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int(structure, "width", &width) ||
!gst_structure_get_int(structure, "height", &height))
{
GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps);
return GST_FLOW_NOT_NEGOTIATED;
}
GstBuffer *newbuf = llgst_buffer_new();
GstBuffer *newbuf = gst_buffer_new();
bool made_bufferdata_ptr = false;
#define MAXDEPTHHACK 4
@@ -349,19 +379,19 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
GstCaps *desired_caps;
GstStructure *desired_struct;
desired_caps = llgst_caps_copy (caps);
desired_struct = llgst_caps_get_structure (desired_caps, 0);
desired_caps = gst_caps_copy (caps);
desired_struct = gst_caps_get_structure (desired_caps, 0);
GValue value = {0};
g_value_init(&value, G_TYPE_INT);
g_value_set_int(&value, slwantwidth);
llgst_structure_set_value (desired_struct, "width", &value);
gst_structure_set_value (desired_struct, "width", &value);
g_value_unset(&value);
g_value_init(&value, G_TYPE_INT);
g_value_set_int(&value, slwantheight);
llgst_structure_set_value (desired_struct, "height", &value);
gst_structure_set_value (desired_struct, "height", &value);
if (llgst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo),
if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo),
desired_caps))
{
// todo: re-use buffers from a pool?
@@ -372,13 +402,13 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK;
GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf));
GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf);
llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps);
gst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps);
made_bufferdata_ptr = true;
} else {
// peer hates our cap suggestion
INFOMSG("peer hates us :(");
llgst_caps_unref(desired_caps);
gst_caps_unref(desired_caps);
}
}
}
@@ -390,7 +420,7 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK;
GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf));
GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf);
llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps);
gst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps);
}
*buf = GST_BUFFER_CAST(newbuf);
@@ -432,6 +462,20 @@ gst_slvideo_class_init (GstSLVideoClass * klass)
#undef LLGST_DEBUG_FUNCPTR
}
/*
static void
gst_slvideo_update_caps (GstSLVideo * slvideo)
{
GstCaps *caps;
// GStreamer will automatically convert colourspace if necessary.
// GStreamer will automatically resize media to one of these enumerated
// powers-of-two that we ask for (yay GStreamer!)
caps = gst_caps_from_string (SLV_ALLCAPS);
gst_caps_replace (&slvideo->caps, caps);
}
*/
/* initialize the new element
* instantiate pads and add them to element
@@ -454,24 +498,24 @@ gst_slvideo_init (GstSLVideo * filter,
filter->retained_frame_width = filter->width;
filter->retained_frame_height = filter->height;
filter->retained_frame_format = SLV_PF_UNKNOWN;
GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS);
llgst_caps_replace (&filter->caps, caps);
GstCaps *caps = gst_caps_from_string (SLV_ALLCAPS);
gst_caps_replace (&filter->caps, caps);
filter->resize_forced_always = false;
filter->resize_try_width = -1;
filter->resize_try_height = -1;
GST_OBJECT_UNLOCK(filter);
//gst_slvideo_update_caps(filter);
}
static void
gst_slvideo_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
llg_return_if_fail (GST_IS_SLVIDEO (object));
g_return_if_fail (GST_IS_SLVIDEO (object));
switch (prop_id) {
default:
if (prop_id) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
@@ -479,12 +523,10 @@ static void
gst_slvideo_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
llg_return_if_fail (GST_IS_SLVIDEO (object));
g_return_if_fail (GST_IS_SLVIDEO (object));
switch (prop_id) {
default:
if (prop_id) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
@@ -502,7 +544,7 @@ plugin_init (GstPlugin * plugin)
GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin",
0, (gchar*)"Second Life Video Sink");
return llgst_element_register (plugin, "private-slvideo",
return gst_element_register (plugin, "private-slvideo",
GST_RANK_NONE, GST_TYPE_SLVIDEO);
}
@@ -512,20 +554,19 @@ plugin_init (GstPlugin * plugin)
some g++ versions buggily avoid __attribute__((constructor)) functions -
so we provide an explicit plugin init function.
*/
#define PACKAGE (gchar*)"packagehack"
// this macro quietly refers to PACKAGE internally
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
(gchar*)"private-slvideoplugin",
(gchar*)"SL Video sink plugin",
plugin_init, (gchar*)"0.1", (gchar*)GST_LICENSE_UNKNOWN,
(gchar*)"Second Life",
(gchar*)"http://www.secondlife.com/");
#undef PACKAGE
void gst_slvideo_init_class (void)
{
ll_gst_plugin_register_static (&gst_plugin_desc);
DEBUGMSG("CLASS INIT");
gst_plugin_register_static( GST_VERSION_MAJOR,
GST_VERSION_MINOR,
(const gchar *)"private-slvideoplugin",
(gchar *)"SL Video sink plugin",
plugin_init,
(const gchar *)"0.1",
GST_LICENSE_UNKNOWN,
(const gchar *)"Second Life",
(const gchar *)"Second Life",
(const gchar *)"http://www.secondlife.com/" );
}
#endif // LL_GSTREAMER010_ENABLED

View File

@@ -2,9 +2,10 @@
* @file llmediaimplgstreamervidplug.h
* @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Copyright (c) 2007-2009, Linden Research, Inc.
* Copyright (c) 2007-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,6 +29,8 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef __GST_SLVIDEO_H__
@@ -39,6 +42,7 @@ extern "C" {
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideosink.h>
// #include <glib/gthread.h>
}
G_BEGIN_DECLS

View File

@@ -2,9 +2,10 @@
* @file media_plugin_gstreamer010.cpp
* @brief GStreamer-0.10 plugin for LLMedia API plugin system
*
* @cond
* $LicenseInfo:firstyear=2007&license=viewergpl$
*
* Copyright (c) 2007-2009, Linden Research, Inc.
* Copyright (c) 2007-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,13 +13,13 @@
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
@@ -28,10 +29,19 @@
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#include "linden_common.h"
// Needed for _getcwd() RC
#ifdef LL_WINDOWS
#include <direct.h>
#include <stdlib.h>
#include <stdio.h>
#endif
#include "llgl.h"
#include "llplugininstance.h"
@@ -43,6 +53,7 @@
extern "C" {
#include <gst/gst.h>
#include <gst/gstelement.h>
}
#include "llmediaimplgstreamer.h"
@@ -50,8 +61,6 @@ extern "C" {
#include "llmediaimplgstreamervidplug.h"
#include "llmediaimplgstreamer_syms.h"
//////////////////////////////////////////////////////////////////////////////
//
class MediaPluginGStreamer010 : public MediaPluginBase
@@ -65,6 +74,8 @@ public:
static bool startup();
static bool closedown();
static void set_gst_plugin_path();
gboolean processGSTEvents(GstBus *bus,
GstMessage *message);
@@ -80,7 +91,7 @@ private:
bool play(double rate);
bool getTimePos(double &sec_out);
static const double MIN_LOOP_SEC = 1.0F;
#define MIN_LOOP_SEC 1.0F
bool mIsLooping;
@@ -136,6 +147,8 @@ private:
bool mSeekWanted;
double mSeekDestination;
std::string mLastTitle;
// Very GStreamer-specific
GMainLoop *mPump; // event pump for this media
@@ -193,149 +206,179 @@ MediaPluginGStreamer010::processGSTEvents(GstBus *bus,
GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING)
{
DEBUGMSG("Got GST message type: %s",
LLGST_MESSAGE_TYPE_NAME (message));
GST_MESSAGE_TYPE_NAME (message));
}
else
{
// TODO: grok 'duration' message type
DEBUGMSG("Got GST message type: %s",
LLGST_MESSAGE_TYPE_NAME (message));
GST_MESSAGE_TYPE_NAME (message));
}
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_BUFFERING: {
// NEEDS GST 0.10.11+
if (llgst_message_parse_buffering)
switch (GST_MESSAGE_TYPE (message))
{
case GST_MESSAGE_BUFFERING:
{
// NEEDS GST 0.10.11+ and America discovered by C.Columbus
gint percent = 0;
llgst_message_parse_buffering(message, &percent);
gst_message_parse_buffering(message, &percent);
DEBUGMSG("GST buffering: %d%%", percent);
}
break;
}
case GST_MESSAGE_STATE_CHANGED: {
GstState old_state;
GstState new_state;
GstState pending_state;
llgst_message_parse_state_changed(message,
&old_state,
&new_state,
&pending_state);
#ifdef LL_GST_REPORT_STATE_CHANGES
// not generally very useful, and rather spammy.
DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s",
get_gst_state_name(old_state),
get_gst_state_name(new_state),
get_gst_state_name(pending_state));
#endif // LL_GST_REPORT_STATE_CHANGES
switch (new_state) {
case GST_STATE_VOID_PENDING:
break;
case GST_STATE_NULL:
break;
case GST_STATE_READY:
setStatus(STATUS_LOADED);
break;
case GST_STATE_PAUSED:
setStatus(STATUS_PAUSED);
break;
case GST_STATE_PLAYING:
setStatus(STATUS_PLAYING);
break;
}
break;
}
case GST_MESSAGE_ERROR: {
GError *err = NULL;
gchar *debug = NULL;
case GST_MESSAGE_STATE_CHANGED: {
GstState old_state;
GstState new_state;
GstState pending_state;
gst_message_parse_state_changed(message,
&old_state,
&new_state,
&pending_state);
#ifdef LL_GST_REPORT_STATE_CHANGES
// not generally very useful, and rather spammy.
DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s",
get_gst_state_name(old_state),
get_gst_state_name(new_state),
get_gst_state_name(pending_state));
#endif // LL_GST_REPORT_STATE_CHANGES
llgst_message_parse_error (message, &err, &debug);
WARNMSG("GST error: %s", err?err->message:"(unknown)");
if (err)
g_error_free (err);
g_free (debug);
mCommand = COMMAND_STOP;
setStatus(STATUS_ERROR);
break;
}
case GST_MESSAGE_INFO: {
if (llgst_message_parse_info)
switch (new_state)
{
case GST_STATE_VOID_PENDING:
break;
case GST_STATE_NULL:
break;
case GST_STATE_READY:
setStatus(STATUS_LOADED);
break;
case GST_STATE_PAUSED:
setStatus(STATUS_PAUSED);
break;
case GST_STATE_PLAYING:
setStatus(STATUS_PLAYING);
break;
}
break;
}
case GST_MESSAGE_ERROR:
{
GError *err = NULL;
gchar *debug = NULL;
gst_message_parse_error (message, &err, &debug);
WARNMSG("GST error: %s", err?err->message:"(unknown)");
if (err)
g_error_free (err);
g_free (debug);
mCommand = COMMAND_STOP;
setStatus(STATUS_ERROR);
break;
}
case GST_MESSAGE_INFO:
{
GError *err = NULL;
gchar *debug = NULL;
llgst_message_parse_info (message, &err, &debug);
gst_message_parse_info (message, &err, &debug);
INFOMSG("GST info: %s", err?err->message:"(unknown)");
if (err)
g_error_free (err);
g_free (debug);
break;
}
break;
}
case GST_MESSAGE_WARNING: {
GError *err = NULL;
gchar *debug = NULL;
llgst_message_parse_warning (message, &err, &debug);
WARNMSG("GST warning: %s", err?err->message:"(unknown)");
if (err)
g_error_free (err);
g_free (debug);
break;
}
case GST_MESSAGE_EOS:
/* end-of-stream */
DEBUGMSG("GST end-of-stream.");
if (mIsLooping)
case GST_MESSAGE_WARNING:
{
DEBUGMSG("looping media...");
double eos_pos_sec = 0.0F;
bool got_eos_position = getTimePos(eos_pos_sec);
GError *err = NULL;
gchar *debug = NULL;
gst_message_parse_warning (message, &err, &debug);
WARNMSG("GST warning: %s", err?err->message:"(unknown)");
if (err)
g_error_free (err);
g_free (debug);
break;
}
case GST_MESSAGE_TAG:
{
GstTagList *new_tags;
if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC)
gst_message_parse_tag( message, &new_tags );
gchar *title = NULL;
if ( gst_tag_list_get_string(new_tags, GST_TAG_TITLE, &title) )
{
// if we know that the movie is really short, don't
// loop it else it can easily become a time-hog
// because of GStreamer spin-up overhead
DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec);
// inject a COMMAND_PAUSE
mCommand = COMMAND_PAUSE;
}
else
{
#undef LLGST_LOOP_BY_SEEKING
// loop with a stop-start instead of a seek, because it actually seems rather
// faster than seeking on remote streams.
#ifdef LLGST_LOOP_BY_SEEKING
// first, try looping by an explicit rewind
bool seeksuccess = seek(0.0);
if (seeksuccess)
//WARMING("Title: %s", title);
std::string newtitle(title);
gst_tag_list_free(new_tags);
if ( newtitle != mLastTitle && !newtitle.empty() )
{
play(1.0);
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
message.setValue("name", newtitle );
sendMessage( message );
mLastTitle = newtitle;
}
g_free(title);
}
break;
}
case GST_MESSAGE_EOS:
{
/* end-of-stream */
DEBUGMSG("GST end-of-stream.");
if (mIsLooping)
{
DEBUGMSG("looping media...");
double eos_pos_sec = 0.0F;
bool got_eos_position = getTimePos(eos_pos_sec);
if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC)
{
// if we know that the movie is really short, don't
// loop it else it can easily become a time-hog
// because of GStreamer spin-up overhead
DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec);
// inject a COMMAND_PAUSE
mCommand = COMMAND_PAUSE;
}
else
#endif // LLGST_LOOP_BY_SEEKING
{ // use clumsy stop-start to loop
DEBUGMSG("didn't loop by rewinding - stopping and starting instead...");
stop();
play(1.0);
{
#undef LLGST_LOOP_BY_SEEKING
// loop with a stop-start instead of a seek, because it actually seems rather
// faster than seeking on remote streams.
#ifdef LLGST_LOOP_BY_SEEKING
// first, try looping by an explicit rewind
bool seeksuccess = seek(0.0);
if (seeksuccess)
{
play(1.0);
}
else
#endif // LLGST_LOOP_BY_SEEKING
{ // use clumsy stop-start to loop
DEBUGMSG("didn't loop by rewinding - stopping and starting instead...");
stop();
play(1.0);
}
}
}
}
else // not a looping media
{
// inject a COMMAND_STOP
mCommand = COMMAND_STOP;
}
break;
default:
/* unhandled message */
break;
else // not a looping media
{
// inject a COMMAND_STOP
mCommand = COMMAND_STOP;
}
} break;
default:
/* unhandled message */
break;
}
/* we want to be notified again the next time there is a message
@@ -541,7 +584,7 @@ MediaPluginGStreamer010::pause()
{
DEBUGMSG("pausing media...");
// todo: error-check this?
llgst_element_set_state(mPlaybin, GST_STATE_PAUSED);
gst_element_set_state(mPlaybin, GST_STATE_PAUSED);
return true;
}
@@ -550,7 +593,7 @@ MediaPluginGStreamer010::stop()
{
DEBUGMSG("stopping media...");
// todo: error-check this?
llgst_element_set_state(mPlaybin, GST_STATE_READY);
gst_element_set_state(mPlaybin, GST_STATE_READY);
return true;
}
@@ -561,7 +604,7 @@ MediaPluginGStreamer010::play(double rate)
DEBUGMSG("playing media... rate=%f", rate);
// todo: error-check this?
llgst_element_set_state(mPlaybin, GST_STATE_PLAYING);
gst_element_set_state(mPlaybin, GST_STATE_PLAYING);
return true;
}
@@ -590,7 +633,7 @@ MediaPluginGStreamer010::seek(double time_sec)
bool success = false;
if (mDoneInit && mPlaybin)
{
success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME,
success = gst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME,
GstSeekFlags(GST_SEEK_FLAG_FLUSH |
GST_SEEK_FLAG_KEY_UNIT),
GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND),
@@ -609,11 +652,9 @@ MediaPluginGStreamer010::getTimePos(double &sec_out)
{
gint64 pos;
GstFormat timefmt = GST_FORMAT_TIME;
got_position =
llgst_element_query_position &&
llgst_element_query_position(mPlaybin,
&timefmt,
&pos);
got_position = gst_element_query_position(mPlaybin,
&timefmt,
&pos);
got_position = got_position
&& (timefmt == GST_FORMAT_TIME);
// GStreamer may have other ideas, but we consider the current position
@@ -655,7 +696,7 @@ MediaPluginGStreamer010::load()
DEBUGMSG("setting up media...");
mIsLooping = false;
mVolume = 0.1234567; // minor hack to force an initial volume update
mVolume = (float) 0.1234567; // minor hack to force an initial volume update
// Create a pumpable main-loop for this media
mPump = g_main_loop_new (NULL, FALSE);
@@ -666,7 +707,7 @@ MediaPluginGStreamer010::load()
}
// instantiate a playbin element to do the hard work
mPlaybin = llgst_element_factory_make ("playbin", "play");
mPlaybin = gst_element_factory_make ("playbin", "play");
if (!mPlaybin)
{
setStatus(STATUS_ERROR);
@@ -674,21 +715,21 @@ MediaPluginGStreamer010::load()
}
// get playbin's bus
GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin));
GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mPlaybin));
if (!bus)
{
setStatus(STATUS_ERROR);
return false; // error
}
mBusWatchID = llgst_bus_add_watch (bus,
mBusWatchID = gst_bus_add_watch (bus,
llmediaimplgstreamer_bus_callback,
this);
llgst_object_unref (bus);
gst_object_unref (bus);
if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) {
// instantiate a custom video sink
mVideoSink =
GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo"));
GST_SLVIDEO(gst_element_factory_make ("private-slvideo", "slvideo"));
if (!mVideoSink)
{
WARNMSG("Could not instantiate private-slvideo element.");
@@ -718,8 +759,8 @@ MediaPluginGStreamer010::unload ()
if (mPlaybin)
{
llgst_element_set_state (mPlaybin, GST_STATE_NULL);
llgst_object_unref (GST_OBJECT (mPlaybin));
gst_element_set_state (mPlaybin, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (mPlaybin));
mPlaybin = NULL;
}
@@ -752,7 +793,10 @@ MediaPluginGStreamer010::startup()
// Init the glib type system - we need it.
g_type_init();
set_gst_plugin_path();
/*
// Get symbols!
#if LL_DARWIN
if (! grab_gst_syms("libgstreamer-0.10.dylib",
@@ -768,24 +812,24 @@ MediaPluginGStreamer010::startup()
WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled.");
return false;
}
if (llgst_segtrap_set_enabled)
{
llgst_segtrap_set_enabled(FALSE);
}
else
{
WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught.");
}
*/
// if (gst_segtrap_set_enabled)
// {
gst_segtrap_set_enabled(FALSE);
// }
// else
// {
// WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught.");
// }
/*
#if LL_LINUX
// Gstreamer tries a fork during init, waitpid-ing on it,
// which conflicts with any installed SIGCHLD handler...
struct sigaction tmpact, oldact;
if (llgst_registry_fork_set_enabled) {
if (gst_registry_fork_set_enabled) {
// if we can disable SIGCHLD-using forking behaviour,
// do it.
llgst_registry_fork_set_enabled(false);
gst_registry_fork_set_enabled(false);
}
else {
// else temporarily install default SIGCHLD handler
@@ -796,24 +840,24 @@ MediaPluginGStreamer010::startup()
sigaction(SIGCHLD, &tmpact, &oldact);
}
#endif // LL_LINUX
*/
// Protect against GStreamer resetting the locale, yuck.
static std::string saved_locale;
saved_locale = setlocale(LC_ALL, NULL);
// finally, try to initialize GStreamer!
GError *err = NULL;
gboolean init_gst_success = llgst_init_check(NULL, NULL, &err);
gboolean init_gst_success = gst_init_check(NULL, NULL, &err);
// restore old locale
setlocale(LC_ALL, saved_locale.c_str() );
/*
#if LL_LINUX
// restore old SIGCHLD handler
if (!llgst_registry_fork_set_enabled)
if (!gst_registry_fork_set_enabled)
sigaction(SIGCHLD, &oldact, NULL);
#endif // LL_LINUX
*/
if (!init_gst_success) // fail
{
if (err)
@@ -827,16 +871,139 @@ MediaPluginGStreamer010::startup()
}
return false;
}
// Set up logging facilities
gst_debug_remove_log_function( gst_debug_log_default );
// gst_debug_add_log_function( gstreamer_log, NULL );
// Init our custom plugins - only really need do this once.
gst_slvideo_init_class();
/*
// List the plugins GStreamer can find
LL_DEBUGS("MediaImpl") << "Found GStreamer plugins:" << LL_ENDL;
GList *list;
GstRegistry *registry = gst_registry_get_default();
std::string loaded = "";
for (list = gst_registry_get_plugin_list(registry);
list != NULL;
list = g_list_next(list))
{
GstPlugin *list_plugin = (GstPlugin *)list->data;
(bool)gst_plugin_is_loaded(list_plugin) ? loaded = "Yes" : loaded = "No";
LL_DEBUGS("MediaImpl") << gst_plugin_get_name(list_plugin) << ", loaded? " << loaded << LL_ENDL;
}
gst_plugin_list_free(list);
*/
mDoneInit = true;
}
return true;
}
void MediaPluginGStreamer010::set_gst_plugin_path()
{
// Linux sets GST_PLUGIN_PATH in wrapper.sh, not here.
#if LL_WINDOWS || LL_DARWIN
std::string imp_dir = "";
// Get the current working directory:
#if LL_WINDOWS
char* raw_dir;
raw_dir = _getcwd(NULL,0);
if( raw_dir != NULL )
{
imp_dir = std::string( raw_dir );
}
#elif LL_DARWIN
CFBundleRef main_bundle = CFBundleGetMainBundle();
if( main_bundle != NULL )
{
CFURLRef bundle_url = CFBundleCopyBundleURL( main_bundle );
if( bundle_url != NULL )
{
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
char raw_dir[MAXPATHLEN];
if( CFURLGetFileSystemRepresentation( bundle_url, true, (UInt8 *)raw_dir, MAXPATHLEN) )
{
imp_dir = std::string( raw_dir ) + "/Contents/MacOS/";
}
CFRelease(bundle_url);
}
}
#endif
if( imp_dir == "" )
{
WARNMSG("Could not get application directory, not setting GST_PLUGIN_PATH.");
return;
}
DEBUGMSG("Imprudence is installed at %s", imp_dir);
// ":" on Mac and 'Nix, ";" on Windows
std::string separator = G_SEARCHPATH_SEPARATOR_S;
// Grab the current path, if it's set.
std::string old_plugin_path = "";
char *old_path = getenv("GST_PLUGIN_PATH");
if(old_path == NULL)
{
DEBUGMSG("Did not find user-set GST_PLUGIN_PATH.");
}
else
{
old_plugin_path = separator + std::string( old_path );
}
// Search both Imprudence and Imprudence\lib\gstreamer-plugins.
// But we also want to search the path the user has set, if any.
std::string plugin_path =
"GST_PLUGIN_PATH=" +
#if LL_WINDOWS
imp_dir + "\\lib\\gstreamer-plugins" +
#elif LL_DARWIN
imp_dir + separator +
imp_dir + "/../Resources/lib/gstreamer-plugins" +
#endif
old_plugin_path;
int put_result;
// Place GST_PLUGIN_PATH in the environment settings
#if LL_WINDOWS
put_result = _putenv( (char*)plugin_path.c_str() );
#elif LL_DARWIN
put_result = putenv( (char*)plugin_path.c_str() );
#endif
if( put_result == -1 )
{
WARNMSG("Setting GST_PLUGIN_PATH failed!");
}
else
{
DEBUGMSG("GST_PLUGIN_PATH set to %s", getenv("GST_PLUGIN_PATH"));
}
// Don't load system plugins. We only want to use ours, to avoid conflicts.
#if LL_WINDOWS
put_result = _putenv( "GST_PLUGIN_SYSTEM_PATH=\"\"" );
#elif LL_DARWIN
put_result = putenv( "GST_PLUGIN_SYSTEM_PATH=\"\"" );
#endif
if( put_result == -1 )
{
WARNMSG("Setting GST_PLUGIN_SYSTEM_PATH=\"\" failed!");
}
#endif // LL_WINDOWS || LL_DARWIN
}
void
MediaPluginGStreamer010::sizeChanged()
@@ -878,7 +1045,7 @@ MediaPluginGStreamer010::closedown()
if (!mDoneInit)
return false; // error
ungrab_gst_syms();
// ungrab_gst_syms();
mDoneInit = false;
@@ -899,11 +1066,10 @@ std::string
MediaPluginGStreamer010::getVersion()
{
std::string plugin_version = "GStreamer010 media plugin, GStreamer version ";
if (mDoneInit &&
llgst_version)
if (mDoneInit) // && gst_version)
{
guint major, minor, micro, nano;
llgst_version(&major, &minor, &micro, &nano);
gst_version(&major, &minor, &micro, &nano);
plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO);
}
else
@@ -945,33 +1111,6 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string)
message.setValue("plugin_version", getVersion());
sendMessage(message);
// Plugin gets to decide the texture parameters to use.
message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
// lame to have to decide this now, it depends on the movie. Oh well.
mDepth = 4;
mCurrentWidth = 1;
mCurrentHeight = 1;
mPreviousWidth = 1;
mPreviousHeight = 1;
mNaturalWidth = 1;
mNaturalHeight = 1;
mWidth = 1;
mHeight = 1;
mTextureWidth = 1;
mTextureHeight = 1;
message.setValueU32("format", GL_RGBA);
message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV);
message.setValueS32("depth", mDepth);
message.setValueS32("default_width", mWidth);
message.setValueS32("default_height", mHeight);
message.setValueU32("internalformat", GL_RGBA8);
message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale
sendMessage(message);
}
else if(message_name == "idle")
{
@@ -1036,7 +1175,36 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string)
}
else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
{
if(message_name == "size_change")
if(message_name == "init")
{
// Plugin gets to decide the texture parameters to use.
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
// lame to have to decide this now, it depends on the movie. Oh well.
mDepth = 4;
mCurrentWidth = 1;
mCurrentHeight = 1;
mPreviousWidth = 1;
mPreviousHeight = 1;
mNaturalWidth = 1;
mNaturalHeight = 1;
mWidth = 1;
mHeight = 1;
mTextureWidth = 1;
mTextureHeight = 1;
message.setValueU32("format", GL_RGBA);
message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV);
message.setValueS32("depth", mDepth);
message.setValueS32("default_width", mWidth);
message.setValueS32("default_height", mHeight);
message.setValueU32("internalformat", GL_RGBA8);
message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale
sendMessage(message);
}
else if(message_name == "size_change")
{
std::string name = message_in.getValue("name");
S32 width = message_in.getValueS32("width");

0
indra/media_plugins/quicktime/CMakeLists.txt Normal file → Executable file
View File

180
indra/media_plugins/quicktime/media_plugin_quicktime.cpp Normal file → Executable file
View File

@@ -1,33 +1,29 @@
/**
/**
* @file media_plugin_quicktime.cpp
* @brief QuickTime plugin for LLMedia API plugin system
*
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008-2009, Linden Research, Inc.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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;
* version 2.1 of the License only.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
*/
#include "linden_common.h"
@@ -102,14 +98,14 @@ private:
message.setValueS32("top", top);
message.setValueS32("right", right);
message.setValueS32("bottom", bottom);
if(mMovieHandle)
{
message.setValueReal("current_time", getCurrentTime());
message.setValueReal("duration", getDuration());
message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle)));
}
sendMessage(message);
}
@@ -117,16 +113,16 @@ private:
static Rect rectFromSize(int width, int height)
{
Rect result;
result.left = 0;
result.top = 0;
result.right = width;
result.bottom = height;
return result;
}
Fixed getPlayRate(void)
{
Fixed result;
@@ -145,25 +141,27 @@ private:
{
result = X2Fix(mPlayRate);
}
return result;
}
void load( const std::string url )
{
if ( url.empty() )
return;
// Stop and unload any existing movie before starting another one.
unload();
setStatus(STATUS_LOADING);
//In case std::string::c_str() makes a copy of the url data,
//make sure there is memory to hold it before allocating memory for handle.
//if fails, NewHandleClear(...) should return NULL.
const char* url_string = url.c_str() ;
Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) );
if ( NULL == handle || noErr != MemError() || NULL == *handle )
{
setStatus(STATUS_ERROR);
@@ -202,7 +200,7 @@ private:
SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this );
setStatus(STATUS_LOADED);
sizeChanged();
};
@@ -239,7 +237,7 @@ private:
DisposeGWorld( mGWorldHandle );
mGWorldHandle = NULL;
};
setStatus(STATUS_NONE);
return true;
@@ -249,7 +247,7 @@ private:
{
unload();
load( url );
return true;
};
@@ -257,7 +255,7 @@ private:
{
if ( ! mMovieHandle )
return false;
// Check to see whether the movie's natural size has updated
{
int width, height;
@@ -275,14 +273,14 @@ private:
//std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl;
}
}
// sanitize destination size
Rect dest_rect = rectFromSize(mWidth, mHeight);
// media depth won't change
int depth_bits = mDepth * 8;
long rowbytes = mDepth * mTextureWidth;
GWorldPtr old_gworld_handle = mGWorldHandle;
if(mPixels != NULL)
@@ -314,7 +312,7 @@ private:
{
DisposeGWorld( old_gworld_handle );
}
// Set up the movie display matrix
{
// scale movie to fit rect and invert vertically to match opengl image format
@@ -327,7 +325,7 @@ private:
ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) );
SetMovieMatrix( mMovieHandle, &transform );
}
// update movie controller
if ( mMovieController )
{
@@ -345,7 +343,6 @@ private:
return true;
}
static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref )
{
Boolean result = false;
@@ -355,9 +352,9 @@ private:
switch( action )
{
// handle window resizing
case mcActionControllerSizeChanged:
case mcActionControllerSizeChanged:
// Ensure that the movie draws correctly at the new size
self->sizeChanged();
self->sizeChanged();
break;
// Block any movie controller actions that open URLs.
@@ -386,6 +383,7 @@ private:
// self->updateQuickTime();
// TODO ^^^
if ( self->mWidth > 0 && self->mHeight > 0 )
self->setDirty( 0, 0, self->mWidth, self->mHeight );
@@ -434,7 +432,7 @@ private:
MCDoAction( mMovieController, mcActionPlay, (void*)rate );
rewind();
};
MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
setStatus(STATUS_PLAYING);
@@ -462,7 +460,7 @@ private:
if ( mCommand == COMMAND_PAUSE )
{
if ( mStatus == STATUS_PLAYING )
{
{
if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
{
Fixed rate = X2Fix( 0.0 );
@@ -495,7 +493,7 @@ private:
void getMovieNaturalSize(int *movie_width, int *movie_height)
{
Rect rect;
GetMovieNaturalBoundsRect( mMovieHandle, &rect );
int width = ( rect.right - rect.left );
@@ -518,7 +516,7 @@ private:
*movie_width = width;
*movie_height = height;
}
void updateQuickTime(int milliseconds)
{
if ( ! mMovieHandle )
@@ -721,8 +719,8 @@ private:
return false;
// allocate some space and grab it
UInt8* item_data = new UInt8[size + 1];
memset(item_data, 0, (size + 1) * sizeof(UInt8));
UInt8* item_data = new UInt8[ size + 1 ];
memset( item_data, 0, ( size + 1 ) * sizeof( UInt8 ) );
result = QTMetaDataGetItemValue( media_data_ref, item, item_data, size, NULL );
if ( noErr != result )
{
@@ -856,42 +854,12 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
plugin_version += codec.str();
message.setValue("plugin_version", plugin_version);
sendMessage(message);
// Plugin gets to decide the texture parameters to use.
message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
#if defined(LL_WINDOWS)
// Values for Windows
mDepth = 3;
message.setValueU32("format", GL_RGB);
message.setValueU32("type", GL_UNSIGNED_BYTE);
// We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even.
// Padding to a multiple of 3*32 guarantees it'll divide out properly.
message.setValueU32("padding", 32 * 3);
#else
// Values for Mac
mDepth = 4;
message.setValueU32("format", GL_BGRA_EXT);
#ifdef __BIG_ENDIAN__
message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV );
#else
message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8);
#endif
// Pad texture width to a multiple of 32 bytes, to line up with cache lines.
message.setValueU32("padding", 32);
#endif
message.setValueS32("depth", mDepth);
message.setValueU32("internalformat", GL_RGB);
message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
message.setValueBoolean("allow_downsample", true);
sendMessage(message);
}
else if(message_name == "idle")
{
// no response is necessary here.
F64 time = message_in.getValueReal("time");
// Convert time to milliseconds for update()
update((int)(time * 1000.0f));
}
@@ -905,8 +873,6 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
info.mAddress = message_in.getValuePointer("address");
info.mSize = (size_t)message_in.getValueS32("size");
std::string name = message_in.getValue("name");
// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name
// << ", size: " << info.mSize
// << ", address: " << info.mAddress
@@ -929,9 +895,9 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
// This is the currently active pixel buffer. Make sure we stop drawing to it.
mPixels = NULL;
mTextureSegmentName.clear();
// Make sure the movie GWorld is no longer pointed at the shared segment.
sizeChanged();
sizeChanged();
}
mSharedSegments.erase(iter);
}
@@ -952,7 +918,41 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
}
else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
{
if(message_name == "size_change")
if(message_name == "init")
{
// This is the media init message -- all necessary data for initialization should have been received.
// Plugin gets to decide the texture parameters to use.
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
#if defined(LL_WINDOWS)
// Values for Windows
mDepth = 3;
message.setValueU32("format", GL_RGB);
message.setValueU32("type", GL_UNSIGNED_BYTE);
// We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even.
// Padding to a multiple of 3*32 guarantees it'll divide out properly.
message.setValueU32("padding", 32 * 3);
#else
// Values for Mac
mDepth = 4;
message.setValueU32("format", GL_BGRA_EXT);
#ifdef __BIG_ENDIAN__
message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV );
#else
message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8);
#endif
// Pad texture width to a multiple of 32 bytes, to line up with cache lines.
message.setValueU32("padding", 32);
#endif
message.setValueS32("depth", mDepth);
message.setValueU32("internalformat", GL_RGB);
message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
message.setValueBoolean("allow_downsample", true);
sendMessage(message);
}
else if(message_name == "size_change")
{
std::string name = message_in.getValue("name");
S32 width = message_in.getValueS32("width");
@@ -988,9 +988,9 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
mTextureHeight = texture_height;
mMediaSizeChanging = false;
sizeChanged();
update();
};
};
@@ -999,14 +999,14 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
{
std::string uri = message_in.getValue("uri");
load( uri );
sendStatus();
sendStatus();
}
else if(message_name == "mouse_event")
{
std::string event = message_in.getValue("event");
S32 x = message_in.getValueS32("x");
S32 y = message_in.getValueS32("y");
if(event == "down")
{
mouseDown(x, y);
@@ -1099,7 +1099,7 @@ MediaPluginQuickTime::~MediaPluginQuickTime()
void MediaPluginQuickTime::receiveMessage(const char *message_string)
{
// no-op
// no-op
}
// We're building without quicktime enabled. Just refuse to initialize.

View File

@@ -27,19 +27,11 @@ include_directories(
${LLIMAGE_INCLUDE_DIRS}
${LLRENDER_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
${LLQTWEBKIT_INCLUDE_DIR}
)
### media_plugin_webkit
if(NOT WORD_SIZE EQUAL 32)
if(WINDOWS)
add_definitions(/FIXED:NO)
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
add_definitions(-fPIC)
endif(WINDOWS)
endif(NOT WORD_SIZE EQUAL 32)
set(media_plugin_webkit_SOURCE_FILES
media_plugin_webkit.cpp
)
@@ -59,11 +51,9 @@ set(media_plugin_webkit_LINK_LIBRARIES
# Select which VolumeCatcher implementation to use
if (LINUX)
if (PULSEAUDIO_FOUND)
if (PULSEAUDIO)
list(APPEND media_plugin_webkit_SOURCE_FILES linux_volume_catcher.cpp)
else (PULSEAUDIO_FOUND)
list(APPEND media_plugin_webkit_SOURCE_FILES dummy_volume_catcher.cpp)
endif (PULSEAUDIO_FOUND)
endif (PULSEAUDIO)
list(APPEND media_plugin_webkit_LINK_LIBRARIES
${UI_LIBRARIES} # for glib/GTK
)
@@ -77,6 +67,9 @@ elseif (DARWIN)
)
elseif (WINDOWS)
list(APPEND media_plugin_webkit_SOURCE_FILES windows_volume_catcher.cpp)
else (LINUX)
# All other platforms use the dummy volume catcher for now.
list(APPEND media_plugin_webkit_SOURCE_FILES dummy_volume_catcher.cpp)
endif (LINUX)
set_source_files_properties(${media_plugin_webkit_HEADER_FILES}

37
indra/media_plugins/webkit/dummy_volume_catcher.cpp Executable file → Normal file
View File

@@ -3,26 +3,33 @@
* @brief A null implementation of the "VolumeCatcher" class for platforms where it's not implemented yet.
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* 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;
* version 2.1 of the License only.
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* 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.
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/

40
indra/media_plugins/webkit/linux_volume_catcher.cpp Executable file → Normal file
View File

@@ -3,26 +3,33 @@
* @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* 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;
* version 2.1 of the License only.
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* 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.
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
@@ -35,8 +42,9 @@
5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call
*/
# include <set> //imprudence
#include "linden_common.h"
#include <set>
#include "volume_catcher.h"

View File

@@ -0,0 +1,56 @@
/**
* @file linux_volume_catcher.h
* @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/
#ifndef LINUX_VOLUME_CATCHER_H
#define LINUX_VOLUME_CATCHER_H
#include "linden_common.h"
class LinuxVolumeCatcherImpl;
class LinuxVolumeCatcher
{
public:
LinuxVolumeCatcher();
~LinuxVolumeCatcher();
void setVolume(F32 volume); // 0.0 - 1.0
void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume
private:
LinuxVolumeCatcherImpl *pimpl;
};
#endif // LINUX_VOLUME_CATCHER_H

View File

View File

37
indra/media_plugins/webkit/mac_volume_catcher.cpp Executable file → Normal file
View File

@@ -3,26 +3,33 @@
* @brief A Mac OS X specific hack to control the volume level of all audio channels opened by a process.
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* 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;
* version 2.1 of the License only.
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* 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.
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/

119
indra/media_plugins/webkit/media_plugin_webkit.cpp Normal file → Executable file
View File

@@ -44,6 +44,7 @@
#include "llpluginmessage.h"
#include "llpluginmessageclasses.h"
#include "media_plugin_base.h"
#include <iomanip>
// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified
#if LL_LINUX
@@ -64,7 +65,6 @@ extern "C" {
# include <unistd.h>
# include <stdlib.h>
#endif
#include <iomanip>
#if LL_WINDOWS
// *NOTE:Mani - This captures the module handle for the dll. This is used below
@@ -78,6 +78,20 @@ extern "C" {
}
#endif
#ifdef LL_STANDALONE
#include <qglobal.h>
#elif defined(LL_LINUX)
// We don't provide Qt headers for non-standalone, therefore define this here.
// Our prebuilt is built with QT_NAMESPACE undefined.
#define QT_MANGLE_NAMESPACE(name) name
#define Q_INIT_RESOURCE(name) \
do { extern int QT_MANGLE_NAMESPACE(qInitResources_ ## name) (); \
QT_MANGLE_NAMESPACE(qInitResources_ ## name) (); } while (0)
#else
// Apparently this symbol doesn't exist in the windows and Mac tar balls provided by LL.
#define Q_INIT_RESOURCE(name) /*nothing*/
#endif
////////////////////////////////////////////////////////////////////////////////
//
class MediaPluginWebKit :
@@ -123,7 +137,6 @@ private:
F32 mBackgroundR;
F32 mBackgroundG;
F32 mBackgroundB;
std::string mTarget;
VolumeCatcher mVolumeCatcher;
@@ -312,7 +325,11 @@ private:
LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
// create single browser window
mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget);
#if LLQTWEBKIT_API_VERSION >= 2
mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow(mWidth, mHeight /*, mTarget*/ ); // We don't have mTarget yet.
#else
mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight );
#endif
// tell LLQtWebKit about the size of the browser window
LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
@@ -322,6 +339,12 @@ private:
// append details to agent string
LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
// Viewer 2+ -- MC
#if LL_WINDOWS
// Set up window open behavior
LLQtWebKit::getInstance()->setWindowOpenBehavior(mBrowserWindowId, LLQtWebKit::WOB_SIMULATE_BLANK_HREF_CLICK);
#endif
#if !LL_QTWEBKIT_USES_PIXMAPS
// don't flip bitmap
@@ -513,9 +536,16 @@ private:
void onClickLinkHref(const EventType& event)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
#if LLQTWEBKIT_API_VERSION >= 2
message.setValue("uri", event.getEventUri());
message.setValue("target", event.getStringValue());
message.setValue("uuid", event.getStringValue2());
#else
// This will work as long as we don't need "uuid", which will be needed for MoaP.
message.setValue("uri", event.getStringValue());
message.setValue("target", event.getStringValue2());
message.setValueU32("target_type", event.getLinkType());
#endif
sendMessage(message);
}
@@ -524,10 +554,13 @@ private:
void onClickLinkNoFollow(const EventType& event)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
#if LLQTWEBKIT_API_VERSION >= 2
message.setValue("uri", event.getEventUri());
#else
message.setValue("uri", event.getStringValue());
#endif
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
// virtual
@@ -540,42 +573,6 @@ private:
// message.setValueBoolean("dead", (event.getIntValue() != 0))
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
// virtual
void onWindowCloseRequested(const EventType& event)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request");
message.setValue("uuid", event.getStringValue());
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
// virtual
void onWindowGeometryChangeRequested(const EventType& event)
{
int x, y, width, height;
event.getRectValue(x, y, width, height);
// This sometimes gets called with a zero-size request. Don't pass these along.
if(width > 0 && height > 0)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change");
message.setValue("uuid", event.getStringValue());
message.setValueS32("x", x);
message.setValueS32("y", y);
message.setValueS32("width", width);
message.setValueS32("height", height);
sendMessage(message);
}
}
////////////////////////////////////////////////////////////////////////////////
// virtual
std::string onRequestFilePicker( const EventType& eventIn )
{
return blockingPickFile();
}
LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
{
@@ -721,26 +718,6 @@ private:
}
}
std::string mPickedFile;
std::string blockingPickFile(void)
{
mPickedFile.clear();
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
message.setValueBoolean("blocking_request", true);
// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
sendMessage(message);
return mPickedFile;
}
void onPickFileResponse(const std::string &file)
{
mPickedFile = file;
}
};
@@ -766,6 +743,9 @@ MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_
mJavascriptEnabled = true; // default to on
mPluginsEnabled = true; // default to on
mUserAgent = "LLPluginMedia Web Browser";
// Initialize WebCore resource.
Q_INIT_RESOURCE(WebCore);
}
MediaPluginWebKit::~MediaPluginWebKit()
@@ -879,8 +859,6 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)
{
if(message_name == "init")
{
mTarget = message_in.getValue("target");
// This is the media init message -- all necessary data for initialization should have been received.
if(initBrowser())
{
@@ -1100,14 +1078,10 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)
LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
checkEditState();
}
if(message_name == "pick_file_response")
{
onPickFileResponse(message_in.getValue("file"));
}
else
{
// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
}
};
}
else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
{
@@ -1207,17 +1181,6 @@ void MediaPluginWebKit::receiveMessage(const char *message_string)
}
}
}
else if(message_name == "proxy_window_opened")
{
std::string target = message_in.getValue("target");
std::string uuid = message_in.getValue("uuid");
LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid);
}
else if(message_name == "proxy_window_closed")
{
std::string uuid = message_in.getValue("uuid");
LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid);
}
else
{
// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;

37
indra/media_plugins/webkit/volume_catcher.h Executable file → Normal file
View File

@@ -3,26 +3,33 @@
* @brief Interface to a class with platform-specific implementations that allows control of the audio volume of all sources in the current process.
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* 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;
* version 2.1 of the License only.
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* 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.
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/

37
indra/media_plugins/webkit/windows_volume_catcher.cpp Executable file → Normal file
View File

@@ -3,26 +3,33 @@
* @brief A Windows implementation of volume level control of all audio channels opened by a process.
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* 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;
* version 2.1 of the License only.
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* 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.
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
* @endcond
*/

View File

@@ -39,8 +39,9 @@
#include "llviewercontrol.h"
#include "llviewerimage.h"
#include "llviewerwindow.h"
#include "llversionviewer.h"
#include "llviewerimagelist.h"
//#include "viewerversion.h"
#include "llpluginclassmedia.h"
#include "llevent.h" // LLSimpleListener
@@ -241,13 +242,15 @@ LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& textur
// static
std::string LLViewerMedia::getCurrentUserAgent()
{
// Don't include version, channel, or skin -- MC
// Don't use user-visible string to avoid
// punctuation and strange characters.
std::string skin_name = gSavedSettings.getString("SkinCurrent");
//std::string skin_name = gSavedSettings.getString("SkinCurrent");
// Just in case we need to check browser differences in A/B test
// builds.
std::string channel = gSavedSettings.getString("VersionChannelName");
//std::string channel = gSavedSettings.getString("VersionChannelName");
// append our magic version number string to the browser user agent id
// See the HTTP 1.0 and 1.1 specifications for allowed formats:
@@ -257,9 +260,10 @@ std::string LLViewerMedia::getCurrentUserAgent()
// http://www.mozilla.org/build/revised-user-agent-strings.html
std::ostringstream codec;
codec << "SecondLife/";
codec << LL_VERSION_MAJOR << "." << LL_VERSION_MINOR << "." << LL_VERSION_PATCH << "." << LL_VERSION_BUILD;
codec << " (" << channel << "; " << skin_name << " skin)";
llinfos << codec.str() << llendl;
codec << "C64 Basic V2";
//codec << ViewerVersion::getImpMajorVersion() << "." << ViewerVersion::getImpMinorVersion() << "." << ViewerVersion::getImpPatchVersion() << " " << ViewerVersion::getImpTestVersion();
//codec << " (" << channel << "; " << skin_name << " skin)";
// llinfos << codec.str() << llendl;
return codec.str();
}
@@ -468,7 +472,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
// In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this
// is what we always used before this change)
std::string linden_user_dir = gDirUtilp->getLindenUserDir();
if (!linden_user_dir.empty())
if ( ! linden_user_dir.empty() )
{
// gDirUtilp->getLindenUserDir() is whole path, not just Linden name
user_data_path = linden_user_dir;
@@ -489,7 +493,22 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
{
LLPluginClassMedia* media_source = new LLPluginClassMedia(owner);
media_source->setSize(default_width, default_height);
if (media_source->init(launcher_name, plugin_name, false, user_data_path))
media_source->setUserDataPath(user_data_path);
media_source->setLanguageCode(LLUI::getLanguage());
// collect 'cookies enabled' setting from prefs and send to embedded browser
bool cookies_enabled = gSavedSettings.getBOOL( "BrowserCookiesEnabled" );
media_source->enable_cookies( cookies_enabled );
// collect 'plugins enabled' setting from prefs and send to embedded browser
bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" );
media_source->setPluginsEnabled( plugins_enabled );
// collect 'javascript enabled' setting from prefs and send to embedded browser
bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );
media_source->setJavascriptEnabled( javascript_enabled );
if (media_source->init(launcher_name, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")))
{
return media_source;
}
@@ -500,7 +519,12 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
}
}
}
LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL;
LLSD args;
args["MIME_TYPE"] = media_type;
LLNotifications::instance().add("NoPlugin", args);
return NULL;
}
@@ -715,12 +739,8 @@ void LLViewerMediaImpl::navigateHome()
}
//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::navigateTo(const std::string& _url, const std::string& mime_type, bool rediscover_type)
void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type)
{
// trim whitespace from front and back of URL - fixes EXT-5363
std::string url(_url);
LLStringUtil::trim(url);
if(rediscover_type)
{
@@ -729,12 +749,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& _url, const std::string& m
if(scheme.empty() || "http" == scheme || "https" == scheme)
{
// If we don't set an Accept header, LLHTTPClient will add one like this:
// Accept: application/llsd+xml
// which is really not what we want.
LLSD headers = LLSD::emptyMap();
headers["Accept"] = "*/*";
LLHTTPClient::getHeaderOnly(url, new LLMimeDiscoveryResponder(this), headers, 10.0f);
LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this));
}
else if("data" == scheme || "file" == scheme || "about" == scheme)
{
@@ -788,7 +803,38 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
if (mMediaSource)
{
result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask);
// FIXME: THIS IS SO WRONG.
// Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
if( MASK_CONTROL & mask )
{
if( 'C' == key )
{
mMediaSource->copy();
result = true;
}
else
if( 'V' == key )
{
mMediaSource->paste();
result = true;
}
else
if( 'X' == key )
{
mMediaSource->cut();
result = true;
}
}
if(!result)
{
LLSD native_key_data = LLSD::emptyMap();
result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data);
// Since the viewer internal event dispatching doesn't give us key-up events, simulate one here.
(void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data);
}
}
return result;
@@ -805,7 +851,9 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
if (uni_char >= 32 // discard 'control' characters
&& uni_char != 127) // SDL thinks this is 'delete' - yuck.
{
mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE));
LLSD native_key_data = LLSD::emptyMap();
mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data);
}
}

View File

@@ -580,9 +580,9 @@
<key>linux</key>
<map>
<key>md5sum</key>
<string>c829b638b6eef71ca63418cb9aea46a2</string>
<string>2cd3f6499f8444f1d119d097e4047252</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gstreamer-linux-20080613.tar.bz2</uri>
<uri>http://imprudenceviewer.org/download/libs/gstreamer-0.10.24-linux-20091125.tar.bz2</uri>
</map>
<key>linux64</key>
<map>
@@ -606,9 +606,9 @@
<key>linux</key>
<map>
<key>md5sum</key>
<string>21c16a74f8fc9a62e3ab944a6eb7403d</string>
<string>349ee367e0ac1e878b24b66e449c6ff8</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gtk-atk-pango-glib-linux-20080616.tar.bz</uri>
<uri>http://imprudenceviewer.org/download/libs/gtk-etc-linux-20101106.1.tar.bz2</uri>
</map>
<key>windows</key>
<map>
@@ -619,7 +619,57 @@
</map>
</map>
</map>
<key>havok</key>
<key>glib</key>
<map>
<key>description</key>
<string>GLib is a library containing many useful C routines for things such as trees, hashes, and lists.</string>
<key>license</key>
<string>gpl</string>
<key>packages</key>
<map>
<key>darwin</key>
<map>
<key>md5sum</key>
<string>6cc5ce1fafd10299fdb890b3d4c3cf53</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-darwin-20080817.tar.bz2</uri>
</map>
<key>linux</key>
<map>
<key>md5sum</key>
<string>2f1a9e14f9213c2c9564c1c1cfdd6d47</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-linux-20080817.tar.bz2</uri>
</map>
<key>windows</key>
<map>
<key>md5sum</key>
<string>3d5e29d444dde4815b36082eedfc775a</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-windows-20080817.tar.bz2</uri>
</map>
</map>
</map>
<key>dbusglib</key>
<map>
<key>copyright</key>
<string>Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc.</string>
<key>description</key>
<string>dbus/dbus-glib: headers only</string>
<key>license</key>
<string>AFL2.1</string>
<key>packages</key>
<map>
<key>linux</key>
<map>
<key>md5sum</key>
<string>eb25444142d4102b0ce1b7ffaadb071e</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbusglib-linux-20080707.tar.bz2</uri>
</map>
</map>
</map>
<key>havok</key>
<map>
<key>copyright</key>
<string>on file</string>
@@ -870,16 +920,16 @@ anguage Infrstructure (CLI) international standard</string>
<key>darwin</key>
<map>
<key>md5sum</key>
<string>7f818f13faf7c02838fe66f7d27e1913</string>
<string>34d9e4c93678a422cf80521bf0cd7628</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-darwin-20091124.tar.bz2</uri>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-4.6-darwin-20100914.tar.bz2</uri>
</map>
<key>linux</key>
<map>
<key>md5sum</key>
<string>ffede2775355676096b1085cbb9d0da7</string>
<string>5d743c93b970abe685b185de83001a6e</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-linux-20091117.tar.bz2</uri>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-linux-qt4.6-20100923.tar.bz2</uri>
</map>
<key>windows</key>
<map>
@@ -1101,6 +1151,25 @@ anguage Infrstructure (CLI) international standard</string>
</map>
</map>
</map>
<key>pulseaudio</key>
<map>
<key>copyright</key>
<string>Copyright 2004-2006 Lennart Poettering, Copyright 2006 Pierre Ossman (ossman@cendio.se) for Cendio AB</string>
<key>description</key>
<string>pulseaudio: headers only</string>
<key>license</key>
<string>lgpl</string>
<key>packages</key>
<map>
<key>linux</key>
<map>
<key>md5sum</key>
<string>30cb00069fe2a545fbf7be1070386236</string>
<key>url</key>
<uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/linux-pulse-headers-0.9.14.tar.bz2</uri>
</map>
</map>
</map>
<key>quicktime</key>
<map>
<key>copyright</key>