summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/CMakeLists.txt6
-rw-r--r--indra/newview/app_settings/settings.xml2
-rwxr-xr-xindra/newview/llmediadataclient.cpp627
-rwxr-xr-xindra/newview/llmediadataclient.h263
-rw-r--r--indra/newview/llviewerobject.cpp1
-rw-r--r--indra/newview/llvovolume.cpp53
-rw-r--r--indra/newview/llvovolume.h7
7 files changed, 910 insertions, 49 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 14a37981a6..d368dd5497 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -264,8 +264,7 @@ set(viewer_SOURCE_FILES
llmaniptranslate.cpp
llmapresponders.cpp
llmediactrl.cpp
- llmediadataresponder.cpp
- llmediadatafetcher.cpp
+ llmediadataclient.cpp
llmediaremotectrl.cpp
llmemoryview.cpp
llmenucommands.cpp
@@ -735,8 +734,7 @@ set(viewer_HEADER_FILES
llmanipscale.h
llmaniptranslate.h
llmapresponders.h
- llmediadataresponder.h
- llmediadatafetcher.h
+ llmediadataclient.h
llmediaremotectrl.h
llmemoryview.h
llmenucommands.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 94a5f5c52b..7f96e0761e 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5294,7 +5294,7 @@
<key>Value</key>
<integer>13</integer>
</map>
- <key>PrimMediaFetchQueueDelay</key>
+ <key>PrimMediaRequestQueueDelay</key>
<map>
<key>Comment</key>
<string>Timer delay for fetching media from the queue (in seconds).</string>
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
new file mode 100755
index 0000000000..e3d3f1a96b
--- /dev/null
+++ b/indra/newview/llmediadataclient.cpp
@@ -0,0 +1,627 @@
+/**
+ * @file llmediadataclient.cpp
+ * @brief class for queueing up requests for media data
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-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 "llviewerprecompiledheaders.h"
+
+#include "llmediadataclient.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "llhttpstatuscodes.h"
+#include "llnotifications.h"
+#include "llsdutil.h"
+#include "llmediaentry.h"
+#include "lltextureentry.h"
+#include "llviewerregion.h"
+#include "llvovolume.h"
+
+//
+// When making a request
+// - obtain the "overall interest score" of the object.
+// This would be the sum of the impls' interest scores.
+// - put the request onto a queue sorted by this score
+// (highest score at the front of the queue)
+// - On a timer, once a second, pull off the head of the queue and send
+// the request.
+// - Any request that gets a 503 still goes through the retry logic
+//
+
+// Some helpful logging macros
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLMediaDataClient::Request
+//
+//////////////////////////////////////////////////////////////////////////////////////
+/*static*/U32 LLMediaDataClient::Request::sNum = 0;
+
+LLMediaDataClient::Request::Request(const std::string &cap_name,
+ const LLSD& sd_payload,
+ LLVOVolume *obj,
+ LLMediaDataClient *mdc)
+ : mCapName(cap_name),
+ mPayload(sd_payload),
+ mObject(obj),
+ mNum(++sNum),
+ mRetryCount(0),
+ mMDC(mdc)
+{
+}
+
+LLMediaDataClient::Request::~Request()
+{
+ mMDC = NULL;
+ mObject = NULL;
+}
+
+
+std::string LLMediaDataClient::Request::getCapability() const
+{
+ return getObject()->getRegion()->getCapability(getCapName());
+}
+
+// Helper function to get the "type" of request, which just pokes around to
+// discover it.
+LLMediaDataClient::Request::Type LLMediaDataClient::Request::getType() const
+{
+ if (mCapName == "ObjectMediaNavigate")
+ {
+ return NAVIGATE;
+ }
+ else if (mCapName == "ObjectMedia")
+ {
+ const std::string &verb = mPayload["verb"];
+ if (verb == "GET")
+ {
+ return GET;
+ }
+ else if (verb == "UPDATE")
+ {
+ return UPDATE;
+ }
+ }
+ llassert(false);
+ return GET;
+}
+
+const char *LLMediaDataClient::Request::getTypeAsString() const
+{
+ Type t = getType();
+ switch (t)
+ {
+ case GET:
+ return "GET";
+ break;
+ case UPDATE:
+ return "UPDATE";
+ break;
+ case NAVIGATE:
+ return "NAVIGATE";
+ break;
+ }
+ return "";
+}
+
+
+void LLMediaDataClient::Request::reEnqueue() const
+{
+ // I sure hope this doesn't deref a bad pointer:
+ mMDC->enqueue(this);
+}
+
+std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r)
+{
+ s << "<request>"
+ << "<num>" << r.getNum() << "</num>"
+ << "<type>" << r.getTypeAsString() << "</type>"
+ << "<object_id>" << r.getObject()->getID() << "</object_id>"
+ << "<num_retries>" << r.getRetryCount() << "</num_retries>"
+ << "</request> ";
+ return s;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLMediaDataClient::Responder::RetryTimer
+//
+//////////////////////////////////////////////////////////////////////////////////////
+
+LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr)
+ : LLEventTimer(time), mResponder(mdr)
+{
+}
+
+// virtual
+LLMediaDataClient::Responder::RetryTimer::~RetryTimer()
+{
+ mResponder = NULL;
+}
+
+// virtual
+BOOL LLMediaDataClient::Responder::RetryTimer::tick()
+{
+ // Instead of retrying, we just put the request back onto the queue
+ LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *(mResponder->getRequest()) << "retrying" << LL_ENDL;
+ mResponder->getRequest()->reEnqueue();
+ // Don't fire again
+ return TRUE;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLMediaDataClient::Responder
+//
+//////////////////////////////////////////////////////////////////////////////////////
+
+LLMediaDataClient::Responder::Responder(const request_ptr_t &request)
+ : mRequest(request)
+{
+}
+
+LLMediaDataClient::Responder::~Responder()
+{
+ mRequest = NULL;
+}
+
+/*virtual*/
+void LLMediaDataClient::Responder::error(U32 status, const std::string& reason)
+{
+ extern LLControlGroup gSavedSettings;
+
+ if (status == HTTP_SERVICE_UNAVAILABLE)
+ {
+ F32 retry_timeout = gSavedSettings.getF32("PrimMediaRetryTimerDelay");
+ if (retry_timeout <= 0.0)
+ {
+ retry_timeout = (F32)UNAVAILABLE_RETRY_TIMER_DELAY;
+ }
+ LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
+
+ mRequest->incRetryCount();
+
+ // Start timer (instances are automagically tracked by
+ // InstanceTracker<> and LLEventTimer)
+ new RetryTimer(F32(retry_timeout/*secs*/), this);
+ }
+ else {
+ std::string msg = boost::lexical_cast<std::string>(status) + ": " + reason;
+ LL_INFOS("LLMediaDataClient") << *mRequest << " error(" << msg << ")" << LL_ENDL;
+ LLSD args;
+ args["ERROR"] = msg;
+ LLNotifications::instance().add("ObjectMediaFailure", args);
+ }
+}
+
+
+/*virtual*/
+void LLMediaDataClient::Responder::result(const LLSD& content)
+{
+ LL_INFOS("LLMediaDataClient") << *mRequest << "result : " << ll_pretty_print_sd(content) << LL_ENDL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLMediaDataClient::Comparator
+//
+//////////////////////////////////////////////////////////////////////////////////////
+
+bool LLMediaDataClient::Comparator::operator() (const request_ptr_t &o1, const request_ptr_t &o2) const
+{
+ if (o2.isNull()) return true;
+ if (o1.isNull()) return false;
+
+ // The score is intended to be a measure of how close an object is or
+ // how much screen real estate (interest) it takes up
+ // Further away = lower score.
+ // Lesser interest = lower score
+ // For instance, here are some cases:
+ // 1: Two items with no impl, closest one wins
+ // 2: Two items with an impl: interest should rule, but distance is
+ // still taken into account (i.e. something really close might take
+ // precedence over a large item far away)
+ // 3: One item with an impl, another without: item with impl wins
+ // (XXX is that what we want?)
+ // Calculate the scores for each.
+ F64 o1_score = Comparator::getObjectScore(o1->getObject());
+ F64 o2_score = Comparator::getObjectScore(o2->getObject());
+
+ return ( o1_score > o2_score );
+}
+
+// static
+F64 LLMediaDataClient::Comparator::getObjectScore(const ll_vo_volume_ptr_t &obj)
+{
+ // *TODO: make this less expensive?
+ F32 dist = obj->getRenderPosition().length() + 0.1; // avoids div by 0
+ // square the distance so that they are in the same "unit magnitude" as
+ // the interest (which is an area)
+ dist *= dist;
+ F64 interest = (F64)1;
+ int i = 0;
+ int end = obj->getNumTEs();
+ for ( ; i < end; ++i)
+ {
+ const viewer_media_t &impl = obj->getMediaImpl(i);
+ if (!impl.isNull())
+ {
+ interest += impl->getInterest();
+ }
+ }
+
+ return interest/dist;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLMediaDataClient::PriorityQueue
+// Queue of LLVOVolume smart pointers to request media for.
+//
+//////////////////////////////////////////////////////////////////////////////////////
+
+// dump the queue
+std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::PriorityQueue &q)
+{
+ int i = 0;
+ std::vector<LLMediaDataClient::request_ptr_t>::const_iterator iter = q.c.begin();
+ std::vector<LLMediaDataClient::request_ptr_t>::const_iterator end = q.c.end();
+ while (iter < end)
+ {
+ s << "\t" << i << "]: " << (*iter)->getObject()->getID().asString();
+ iter++;
+ i++;
+ }
+ return s;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLMediaDataClient::QueueTimer
+// Queue of LLVOVolume smart pointers to request media for.
+//
+//////////////////////////////////////////////////////////////////////////////////////
+
+LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc)
+ : LLEventTimer(time), mMDC(mdc)
+{
+ mMDC->setIsRunning(true);
+}
+
+LLMediaDataClient::QueueTimer::~QueueTimer()
+{
+ mMDC->setIsRunning(false);
+ mMDC = NULL;
+}
+
+// virtual
+BOOL LLMediaDataClient::QueueTimer::tick()
+{
+ if (NULL == mMDC->pRequestQueue)
+ {
+ // Shutting down? stop.
+ LL_DEBUGS("LLMediaDataClient") << "queue gone" << LL_ENDL;
+ return TRUE;
+ }
+
+ LLMediaDataClient::PriorityQueue &queue = *(mMDC->pRequestQueue);
+
+ if (queue.empty())
+ {
+ LL_DEBUGS("LLMediaDataClient") << "queue empty: " << queue << LL_ENDL;
+ return TRUE;
+ }
+
+ LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue is: " << queue << LL_ENDL;
+
+ // Peel one off of the items from the queue, and execute request
+ request_ptr_t request = queue.top();
+ llassert(!request.isNull());
+ const ll_vo_volume_ptr_t &object = request->getObject();
+ bool performed_request = false;
+ llassert(!object.isNull());
+ if (!object.isNull() && object->hasMedia())
+ {
+ std::string url = request->getCapability();
+ if (!url.empty())
+ {
+ const LLSD &sd_payload = request->getPayload();
+ LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL;
+
+ // Call the subclass for creating the responder
+ LLHTTPClient::post(url, sd_payload, mMDC->createResponder(request));
+ performed_request = true;
+ }
+ else {
+ LL_INFOS("LLMediaDataClient") << "NOT Sending request for " << *request << ": empty cap url!" << LL_ENDL;
+ }
+ }
+ else {
+ if (!object->hasMedia())
+ {
+ LL_INFOS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL;
+ }
+ }
+ bool exceeded_retries = request->getRetryCount() > LLMediaDataClient::MAX_RETRIES;
+ if (performed_request || exceeded_retries) // Try N times before giving up
+ {
+ if (exceeded_retries)
+ {
+ LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << LLMediaDataClient::MAX_RETRIES << " tries...popping object id " << object->getID() << LL_ENDL;
+ // XXX Should we bring up a warning dialog??
+ }
+ queue.pop();
+ }
+ else {
+ request->incRetryCount();
+ }
+ LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue is now: " << (*(mMDC->pRequestQueue)) << LL_ENDL;
+
+ return queue.empty();
+}
+
+void LLMediaDataClient::startQueueTimer()
+{
+ if (! mQueueTimerIsRunning)
+ {
+ extern LLControlGroup gSavedSettings;
+ F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay");
+ if (queue_timer_delay <= 0.0f)
+ {
+ queue_timer_delay = (F32)LLMediaDataClient::QUEUE_TIMER_DELAY;
+ }
+ LL_INFOS("LLMediaDataClient") << "starting queue timer (delay=" << queue_timer_delay << " seconds)" << LL_ENDL;
+ // LLEventTimer automagically takes care of the lifetime of this object
+ new QueueTimer(queue_timer_delay, this);
+ }
+}
+
+void LLMediaDataClient::stopQueueTimer()
+{
+ mQueueTimerIsRunning = false;
+}
+
+void LLMediaDataClient::request(LLVOVolume *object, const LLSD &payload)
+{
+ if (NULL == object || ! object->hasMedia()) return;
+
+ // Push the object on the priority queue
+ enqueue(new Request(getCapabilityName(), payload, object, this));
+}
+
+void LLMediaDataClient::enqueue(const Request *request)
+{
+ LL_INFOS("LLMediaDataClient") << "Queuing request for " << *request << LL_ENDL;
+ // Push the request on the priority queue
+ // Sadly, we have to const-cast because items put into the queue are not const
+ pRequestQueue->push(const_cast<LLMediaDataClient::Request*>(request));
+ LL_DEBUGS("LLMediaDataClient") << "Queue:" << (*pRequestQueue) << LL_ENDL;
+ // Start the timer if not already running
+ startQueueTimer();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLMediaDataClient
+//
+//////////////////////////////////////////////////////////////////////////////////////
+
+LLMediaDataClient::LLMediaDataClient()
+{
+ pRequestQueue = new PriorityQueue();
+}
+
+
+LLMediaDataClient::~LLMediaDataClient()
+{
+ stopQueueTimer();
+
+ // This should clear the queue, and hopefully call all the destructors.
+ while (! pRequestQueue->empty()) pRequestQueue->pop();
+
+ delete pRequestQueue;
+ pRequestQueue = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLObjectMediaDataClient
+// Subclass of LLMediaDataClient for the ObjectMedia cap
+//
+//////////////////////////////////////////////////////////////////////////////////////
+
+LLMediaDataClient::Responder *LLObjectMediaDataClient::createResponder(const request_ptr_t &request) const
+{
+ return new LLObjectMediaDataClient::Responder(request);
+}
+
+const char *LLObjectMediaDataClient::getCapabilityName() const
+{
+ return "ObjectMedia";
+}
+
+void LLObjectMediaDataClient::fetchMedia(LLVOVolume *object)
+{
+ LLSD sd_payload;
+ sd_payload["verb"] = "GET";
+ sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
+ request(object, sd_payload);
+}
+
+void LLObjectMediaDataClient::updateMedia(LLVOVolume *object)
+{
+ LLSD sd_payload;
+ sd_payload["verb"] = "UPDATE";
+ sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
+ LLSD object_media_data;
+ for (int i=0; i < object->getNumTEs(); i++) {
+ LLTextureEntry *texture_entry = object->getTE(i);
+ llassert((texture_entry->getMediaData() != NULL) == texture_entry->hasMedia());
+ const LLSD &media_data =
+ (texture_entry->getMediaData() == NULL) ? LLSD() : texture_entry->getMediaData()->asLLSD();
+ object_media_data.append(media_data);
+ }
+ sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data;
+
+ LL_INFOS("LLMediaDataClient") << "update media data: " << object->getID() << " " << ll_pretty_print_sd(sd_payload) << LL_ENDL;
+
+ request(object, sd_payload);
+}
+
+/*virtual*/
+void LLObjectMediaDataClient::Responder::result(const LLSD& content)
+{
+ const LLMediaDataClient::Request::Type type = getRequest()->getType();
+ llassert(type == LLMediaDataClient::Request::GET || type == LLMediaDataClient::Request::UPDATE)
+ if (type == LLMediaDataClient::Request::GET)
+ {
+ LL_INFOS("LLMediaDataClient") << *(getRequest()) << "GET returned: " << ll_pretty_print_sd(content) << LL_ENDL;
+
+ // Look for an error
+ if (content.has("error"))
+ {
+ const LLSD &error = content["error"];
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" <<
+ error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
+
+ // XXX Warn user?
+ }
+ else {
+ // Check the data
+ const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY];
+ if (object_id != getRequest()->getObject()->getID())
+ {
+ // NOT good, wrong object id!!
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << "DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL;
+ return;
+ }
+
+ // Otherwise, update with object media data
+ getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY]);
+ }
+ }
+ else if (type == LLMediaDataClient::Request::UPDATE)
+ {
+ // just do what our superclass does
+ LLMediaDataClient::Responder::result(content);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+//
+// LLObjectMediaNavigateClient
+// Subclass of LLMediaDataClient for the ObjectMediaNavigate cap
+//
+//////////////////////////////////////////////////////////////////////////////////////
+LLMediaDataClient::Responder *LLObjectMediaNavigateClient::createResponder(const request_ptr_t &request) const
+{
+ return new LLObjectMediaNavigateClient::Responder(request);
+}
+
+const char *LLObjectMediaNavigateClient::getCapabilityName() const
+{
+ return "ObjectMediaNavigate";
+}
+
+void LLObjectMediaNavigateClient::navigate(LLVOVolume *object, U8 texture_index, const std::string &url)
+{
+ LLSD sd_payload;
+ sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
+ sd_payload[LLMediaEntry::CURRENT_URL_KEY] = url;
+ sd_payload[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)texture_index;
+ request(object, sd_payload);
+}
+
+/*virtual*/
+void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string& reason)
+{
+ // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base
+ // class
+ if (status == HTTP_SERVICE_UNAVAILABLE)
+ {
+ LLMediaDataClient::Responder::error(status, reason);
+ }
+ else {
+ // bounce the face back
+ bounceBack();
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL;
+ }
+}
+
+/*virtual*/
+void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
+{
+ LL_DEBUGS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_pretty_print_sd(content) << LL_ENDL;
+
+ if (content.has("error"))
+ {
+ const LLSD &error = content["error"];
+ int error_code = error["code"];
+
+ if (ERROR_PERMISSION_DENIED_CODE == error_code)
+ {
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL;
+ // bounce the face back
+ bounceBack();
+ }
+ else {
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" <<
+ error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
+ }
+ // XXX Warn user?
+ }
+ else {
+ // just do what our superclass does
+ LLMediaDataClient::Responder::result(content);
+ }
+}
+
+
+void LLObjectMediaNavigateClient::Responder::bounceBack()
+{
+ const LLSD &payload = getRequest()->getPayload();
+ U8 texture_index = (U8)(LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY];
+ viewer_media_t impl = getRequest()->getObject()->getMediaImpl(texture_index);
+ // Find the media entry for this navigate
+ LLMediaEntry* mep = NULL;
+ LLTextureEntry *te = getRequest()->getObject()->getTE(texture_index);
+ if(te)
+ {
+ mep = te->getMediaData();
+ }
+
+ if (mep && impl)
+ {
+ impl->navigateTo(mep->getCurrentURL());
+ }
+}
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
new file mode 100755
index 0000000000..59c4334251
--- /dev/null
+++ b/indra/newview/llmediadataclient.h
@@ -0,0 +1,263 @@
+/**
+ * @file llmediadataclient.h
+ * @brief class for queueing up requests to the media service
+ *
+ * $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$
+ */
+
+#ifndef LL_LLMEDIADATACLIENT_H
+#define LL_LLMEDIADATACLIENT_H
+
+#include "llhttpclient.h"
+#include <queue>
+#include "llrefcount.h"
+#include "lltimer.h"
+
+// Forward decls
+class LLVOVolume;
+
+typedef LLPointer<LLVOVolume> ll_vo_volume_ptr_t;
+
+// This object creates a priority queue for requests.
+// Abstracts the Cap URL, the request, and the responder
+class LLMediaDataClient : public LLRefCount
+{
+public:
+ LOG_CLASS(LLMediaDataClient);
+
+ const static int QUEUE_TIMER_DELAY = 1; // seconds(s)
+ const static int MAX_RETRIES = 4;
+
+ // Constructor
+ LLMediaDataClient();
+
+ // Make the request
+ void request(LLVOVolume *object, const LLSD &payload);
+
+protected:
+ // Destructor
+ virtual ~LLMediaDataClient(); // use unref
+
+ // Request
+ class Request : public LLRefCount
+ {
+ public:
+ enum Type {
+ GET,
+ UPDATE,
+ NAVIGATE
+ };
+
+ Request(const std::string &cap_name, const LLSD& sd_payload, LLVOVolume *obj, LLMediaDataClient *mdc);
+ const std::string &getCapName() const { return mCapName; }
+ const LLSD &getPayload() const { return mPayload; }
+ LLVOVolume *getObject() const { return mObject; }
+
+ U32 getNum() const { return mNum; }
+
+ U32 getRetryCount() const { return mRetryCount; }
+ void incRetryCount() { mRetryCount++; }
+
+ // Note: may return empty string!
+ std::string getCapability() const;
+
+ Type getType() const;
+ const char *getTypeAsString() const;
+
+ // Re-enqueue thyself
+ void reEnqueue() const;
+
+ public:
+ friend std::ostream& operator<<(std::ostream &s, const Request &q);
+
+ protected:
+ virtual ~Request(); // use unref();
+
+ private:
+ std::string mCapName;
+ LLSD mPayload;
+ ll_vo_volume_ptr_t mObject;
+ // Simple tracking
+ const U32 mNum;
+ static U32 sNum;
+ U32 mRetryCount;
+
+ // Back pointer to the MDC...not a ref!
+ LLMediaDataClient *mMDC;
+ };
+ typedef LLPointer<Request> request_ptr_t;
+
+ // Responder
+ class Responder : public LLHTTPClient::Responder
+ {
+ static const int UNAVAILABLE_RETRY_TIMER_DELAY = 5; // secs
+
+ public:
+ Responder(const request_ptr_t &request);
+ //If we get back an error (not found, etc...), handle it here
+ virtual void error(U32 status, const std::string& reason);
+ //If we get back a normal response, handle it here. Default just logs it.
+ virtual void result(const LLSD& content);
+
+ const request_ptr_t &getRequest() const { return mRequest; }
+
+ protected:
+ virtual ~Responder();
+
+ private:
+
+ class RetryTimer : public LLEventTimer
+ {
+ public:
+ RetryTimer(F32 time, Responder *);
+ virtual ~RetryTimer();
+ virtual BOOL tick();
+ private:
+ // back-pointer
+ boost::intrusive_ptr<Responder> mResponder;
+ };
+
+ request_ptr_t mRequest;
+ };
+
+protected:
+
+ void enqueue(const Request*);
+
+ // Subclasses must override this factory method to return a new responder
+ virtual Responder *createResponder(const request_ptr_t &request) const = 0;
+
+ // Subclasses must override to return a cap name
+ virtual const char *getCapabilityName() const = 0;
+
+private:
+
+ // Comparator for PriorityQueue
+ class Comparator
+ {
+ public:
+ bool operator() (const request_ptr_t &o1, const request_ptr_t &o2) const;
+ private:
+ static F64 getObjectScore(const ll_vo_volume_ptr_t &obj);
+ };
+
+ class PriorityQueue : public std::priority_queue<
+ request_ptr_t,
+ std::vector<request_ptr_t>,
+ Comparator >
+ {
+ public:
+ friend std::ostream& operator<<(std::ostream &s, const PriorityQueue &q);
+ };
+
+ friend std::ostream& operator<<(std::ostream &s, const Request &q);
+ friend std::ostream& operator<<(std::ostream &s, const PriorityQueue &q);
+
+ class QueueTimer : public LLEventTimer
+ {
+ public:
+ QueueTimer(F32 time, LLMediaDataClient *mdc);
+ virtual BOOL tick();
+ protected:
+ virtual ~QueueTimer();
+ private:
+ // back-pointer
+ LLPointer<LLMediaDataClient> mMDC;
+ };
+
+ void startQueueTimer();
+ void stopQueueTimer();
+ void setIsRunning(bool val) { mQueueTimerIsRunning = val; }
+
+ bool mQueueTimerIsRunning;
+
+ PriorityQueue *pRequestQueue;
+};
+
+
+// MediaDataResponder specific for the ObjectMedia cap
+class LLObjectMediaDataClient : public LLMediaDataClient
+{
+public:
+ LLObjectMediaDataClient() {}
+ ~LLObjectMediaDataClient() {}
+
+ void fetchMedia(LLVOVolume *object);
+ void updateMedia(LLVOVolume *object);
+
+protected:
+ // Subclasses must override this factory method to return a new responder
+ virtual Responder *createResponder(const request_ptr_t &request) const;
+
+ // Subclasses must override to return a cap name
+ virtual const char *getCapabilityName() const;
+
+ class Responder : public LLMediaDataClient::Responder
+ {
+ public:
+ Responder(const request_ptr_t &request)
+ : LLMediaDataClient::Responder(request) {}
+ virtual void result(const LLSD &content);
+ };
+};
+
+
+// MediaDataResponder specific for the ObjectMediaNavigate cap
+class LLObjectMediaNavigateClient : public LLMediaDataClient
+{
+ // NOTE: from llmediaservice.h
+ static const int ERROR_PERMISSION_DENIED_CODE = 8002;
+
+public:
+ LLObjectMediaNavigateClient() {}
+ ~LLObjectMediaNavigateClient() {}
+
+ void navigate(LLVOVolume *object, U8 texture_index, const std::string &url);
+
+protected:
+ // Subclasses must override this factory method to return a new responder
+ virtual Responder *createResponder(const request_ptr_t &request) const;
+
+ // Subclasses must override to return a cap name
+ virtual const char *getCapabilityName() const;
+
+ class Responder : public LLMediaDataClient::Responder
+ {
+ public:
+ Responder(const request_ptr_t &request)
+ : LLMediaDataClient::Responder(request) {}
+ virtual void error(U32 status, const std::string& reason);
+ virtual void result(const LLSD &content);
+ private:
+ void bounceBack();
+ };
+
+};
+
+
+#endif // LL_LLMEDIADATACLIENT_H
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 05011a1568..1f4f1322fd 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -47,7 +47,6 @@
#include "llframetimer.h"
#include "llinventory.h"
#include "llmaterialtable.h"
-#include "llmediadataresponder.h"
#include "llmutelist.h"
#include "llnamevalue.h"
#include "llprimitive.h"
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index e69779b2dc..583246c23e 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -46,7 +46,6 @@
#include "llvolumemessage.h"
#include "material_codes.h"
#include "message.h"
-#include "llmediadataresponder.h"
#include "llpluginclassmedia.h" // for code in the mediaEvent handler
#include "object_flags.h"
#include "llagentconstants.h"
@@ -69,7 +68,7 @@
#include "pipeline.h"
#include "llsdutil.h"
#include "llmediaentry.h"
-#include "llmediadatafetcher.h"
+#include "llmediadataclient.h"
#include "llagent.h"
const S32 MIN_QUIET_FRAMES_COALESCE = 30;
@@ -86,6 +85,8 @@ F32 LLVOVolume::sLODFactor = 1.f;
F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop
F32 LLVOVolume::sDistanceFactor = 1.0f;
S32 LLVOVolume::sNumLODChanges = 0;
+LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL;
+LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL;
static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
@@ -133,13 +134,15 @@ LLVOVolume::~LLVOVolume()
// static
void LLVOVolume::initClass()
{
- LLMediaDataFetcher::initClass();
+ sObjectMediaClient = new LLObjectMediaDataClient();
+ sObjectMediaNavigateClient = new LLObjectMediaNavigateClient();
}
// static
void LLVOVolume::cleanupClass()
{
- LLMediaDataFetcher::cleanupClass();
+ sObjectMediaClient = NULL;
+ sObjectMediaNavigateClient = NULL;
}
U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
@@ -1621,7 +1624,7 @@ bool LLVOVolume::hasMedia() const
void LLVOVolume::requestMediaDataUpdate()
{
- LLMediaDataFetcher::fetchMedia(this);
+ sObjectMediaClient->fetchMedia(this);
}
void LLVOVolume::cleanUpMediaImpls()
@@ -1752,21 +1755,7 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
llinfos << "broadcasting navigate with URI " << new_location << llendl;
- // Post the navigate to the cap
- std::string cap = getRegion()->getCapability("ObjectMediaNavigate");
- if(cap.empty())
- {
- // XXX *TODO: deal with no cap! It may happen! (retry?)
- LL_WARNS("Media") << "Can't broadcast navigate event -- ObjectMediaNavigate cap is not available" << LL_ENDL;
- return;
- }
-
- // If we got here, the cap is available. Index through all faces that have this media and send the navigate message.
- LLSD sd;
- sd["object_id"] = mID;
- sd["current_url"] = new_location;
- sd["texture_index"] = face_index;
- LLHTTPClient::post(cap, sd, new LLMediaDataResponder("ObjectMediaNavigate", sd, this));
+ sObjectMediaNavigateClient->navigate(this, face_index, new_location);
}
}
break;
@@ -1790,29 +1779,9 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
}
-void LLVOVolume::sendMediaDataUpdate() const
+void LLVOVolume::sendMediaDataUpdate()
{
- std::string url = getRegion()->getCapability("ObjectMedia");
- if (!url.empty())
- {
- LLSD sd_payload;
- sd_payload["verb"] = "UPDATE";
- sd_payload[LLTextureEntry::OBJECT_ID_KEY] = mID;
- LLSD object_media_data;
- for (int i=0; i < getNumTEs(); i++) {
- LLTextureEntry *texture_entry = getTE(i);
- llassert((texture_entry->getMediaData() != NULL) == texture_entry->hasMedia());
- const LLSD &media_data =
- (texture_entry->getMediaData() == NULL) ? LLSD() : texture_entry->getMediaData()->asLLSD();
- object_media_data.append(media_data);
- }
- sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data;
-
- llinfos << "Sending media data: " << getID() << " " << ll_pretty_print_sd(sd_payload) << llendl;
-
- LLHTTPClient::post(url, sd_payload, new LLMediaDataResponder("ObjectMedia", sd_payload, this));
- }
- // XXX *TODO: deal with no cap! It may happen! (retry?)
+ sObjectMediaClient->updateMedia(this);
}
void LLVOVolume::removeMediaImpl(S32 texture_index)
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 9a79b620d5..250c3ed917 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -45,6 +45,8 @@
class LLViewerTextureAnim;
class LLDrawPool;
class LLSelectNode;
+class LLObjectMediaDataClient;
+class LLObjectMediaNavigateClient;
typedef std::vector<viewer_media_t> media_list_t;
@@ -238,7 +240,7 @@ public:
void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent);
// Send media data update to the simulator.
- void sendMediaDataUpdate() const;
+ void sendMediaDataUpdate();
viewer_media_t getMediaImpl(U8 face_id) const;
S32 getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id);
@@ -283,6 +285,9 @@ public:
static F32 sLODFactor; // LOD scale factor
static F32 sDistanceFactor; // LOD distance factor
+ static LLPointer<LLObjectMediaDataClient> sObjectMediaClient;
+ static LLPointer<LLObjectMediaNavigateClient> sObjectMediaNavigateClient;
+
protected:
static S32 sNumLODChanges;