summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt1
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/llmediadataclient.cpp162
-rw-r--r--indra/newview/llmediadataclient.h88
-rw-r--r--indra/newview/llpanelmediasettingsgeneral.cpp3
-rw-r--r--indra/newview/llviewermedia.cpp34
-rw-r--r--indra/newview/llviewermedia.h1
-rw-r--r--indra/newview/llviewermediafocus.cpp6
-rw-r--r--indra/newview/llviewerparcelmedia.cpp6
-rw-r--r--indra/newview/llvovolume.cpp154
-rw-r--r--indra/newview/llvovolume.h14
-rw-r--r--indra/newview/tests/llmediadataclient_test.cpp483
12 files changed, 838 insertions, 125 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index eb2c7688f9..0bfb0023c2 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1603,6 +1603,7 @@ include(LLAddBuildTest)
SET(viewer_TEST_SOURCE_FILES
llagentaccess.cpp
lldateutil.cpp
+ llmediadataclient.cpp
llviewerhelputil.cpp
lllogininstance.cpp
)
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 2f907f97f2..ecad5dfe41 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5294,6 +5294,17 @@
<key>Value</key>
<integer>13</integer>
</map>
+ <key>PrimMediaMaxRetries</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of retries for media queries.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
<key>PrimMediaRequestQueueDelay</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
index 2f2be0561d..3a1b47554c 100644
--- a/indra/newview/llmediadataclient.cpp
+++ b/indra/newview/llmediadataclient.cpp
@@ -46,7 +46,6 @@
#include "llmediaentry.h"
#include "lltextureentry.h"
#include "llviewerregion.h"
-#include "llvovolume.h"
//
// When making a request
@@ -59,7 +58,9 @@
// - Any request that gets a 503 still goes through the retry logic
//
-// Some helpful logging macros
+const F32 LLMediaDataClient::QUEUE_TIMER_DELAY = 1.0; // seconds(s)
+const F32 LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY = 5.0; // secs
+const U32 LLMediaDataClient::MAX_RETRIES = 4;
//////////////////////////////////////////////////////////////////////////////////////
//
@@ -70,7 +71,7 @@
LLMediaDataClient::Request::Request(const std::string &cap_name,
const LLSD& sd_payload,
- LLVOVolume *obj,
+ LLMediaDataClientObject *obj,
LLMediaDataClient *mdc)
: mCapName(cap_name),
mPayload(sd_payload),
@@ -83,6 +84,7 @@ LLMediaDataClient::Request::Request(const std::string &cap_name,
LLMediaDataClient::Request::~Request()
{
+ LL_DEBUGS("LLMediaDataClient") << "~Request" << (*this) << LL_ENDL;
mMDC = NULL;
mObject = NULL;
}
@@ -90,7 +92,7 @@ LLMediaDataClient::Request::~Request()
std::string LLMediaDataClient::Request::getCapability() const
{
- return getObject()->getRegion()->getCapability(getCapName());
+ return getObject()->getCapabilityUrl(getCapName());
}
// Helper function to get the "type" of request, which just pokes around to
@@ -142,6 +144,17 @@ void LLMediaDataClient::Request::reEnqueue() const
mMDC->enqueue(this);
}
+F32 LLMediaDataClient::Request::getRetryTimerDelay() const
+{
+ return (mMDC == NULL) ? LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY :
+ mMDC->mRetryTimerDelay;
+}
+
+U32 LLMediaDataClient::Request::getMaxNumRetries() const
+{
+ return (mMDC == NULL) ? LLMediaDataClient::MAX_RETRIES : mMDC->mMaxNumRetries;
+}
+
std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r)
{
s << "<request>"
@@ -168,6 +181,7 @@ LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr)
// virtual
LLMediaDataClient::Responder::RetryTimer::~RetryTimer()
{
+ LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL;
mResponder = NULL;
}
@@ -195,28 +209,31 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request)
LLMediaDataClient::Responder::~Responder()
{
+ LL_DEBUGS("LLMediaDataClient") << "~Responder" << *(getRequest()) << LL_ENDL;
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;
+ F32 retry_timeout = mRequest->getRetryTimerDelay();
mRequest->incRetryCount();
- // Start timer (instances are automagically tracked by
- // InstanceTracker<> and LLEventTimer)
- new RetryTimer(F32(retry_timeout/*secs*/), this);
+ if (mRequest->getRetryCount() < mRequest->getMaxNumRetries())
+ {
+ LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
+
+ // Start timer (instances are automagically tracked by
+ // InstanceTracker<> and LLEventTimer)
+ new RetryTimer(F32(retry_timeout/*secs*/), this);
+ }
+ else {
+ LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retry count " <<
+ mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;
+ }
}
else {
std::string msg = boost::lexical_cast<std::string>(status) + ": " + reason;
@@ -257,29 +274,25 @@ bool LLMediaDataClient::Comparator::operator() (const request_ptr_t &o1, const r
// Calculate the scores for each.
F64 o1_score = Comparator::getObjectScore(o1->getObject());
F64 o2_score = Comparator::getObjectScore(o2->getObject());
-
- return ( o1_score > o2_score );
+
+ // XXX Weird: a higher score should go earlier, but by observation I notice
+ // that this causes further-away objects load first. This is counterintuitive
+ // to the priority_queue Comparator, which states that this function should
+ // return 'true' if o1 should be *before* o2.
+ // In other words, I'd have expected that the following should return
+ // ( o1_score > o2_score).
+ return ( o1_score < o2_score );
}
// static
-F64 LLMediaDataClient::Comparator::getObjectScore(const ll_vo_volume_ptr_t &obj)
+F64 LLMediaDataClient::Comparator::getObjectScore(const LLMediaDataClientObject::ptr_t &obj)
{
// *TODO: make this less expensive?
- F32 dist = obj->getRenderPosition().length() + 0.1; // avoids div by 0
+ F64 dist = obj->getDistanceFromAvatar() + 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();
- }
- }
+ F64 interest = obj->getTotalMediaInterest() + 1.0;
return interest/dist;
}
@@ -287,7 +300,7 @@ F64 LLMediaDataClient::Comparator::getObjectScore(const ll_vo_volume_ptr_t &obj)
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::PriorityQueue
-// Queue of LLVOVolume smart pointers to request media for.
+// Queue of LLMediaDataClientObject smart pointers to request media for.
//
//////////////////////////////////////////////////////////////////////////////////////
@@ -309,7 +322,7 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::PriorityQueue
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::QueueTimer
-// Queue of LLVOVolume smart pointers to request media for.
+// Queue of LLMediaDataClientObject smart pointers to request media for.
//
//////////////////////////////////////////////////////////////////////////////////////
@@ -321,6 +334,7 @@ LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc)
LLMediaDataClient::QueueTimer::~QueueTimer()
{
+ LL_DEBUGS("LLMediaDataClient") << "~QueueTimer" << LL_ENDL;
mMDC->setIsRunning(false);
mMDC = NULL;
}
@@ -348,10 +362,10 @@ BOOL LLMediaDataClient::QueueTimer::tick()
// 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();
+ const LLMediaDataClientObject *object = request->getObject();
bool performed_request = false;
- llassert(!object.isNull());
- if (!object.isNull() && object->hasMedia())
+ llassert(NULL != object);
+ if (NULL != object && object->hasMedia())
{
std::string url = request->getCapability();
if (!url.empty())
@@ -373,12 +387,13 @@ BOOL LLMediaDataClient::QueueTimer::tick()
LL_INFOS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL;
}
}
- bool exceeded_retries = request->getRetryCount() > LLMediaDataClient::MAX_RETRIES;
+ bool exceeded_retries = request->getRetryCount() > mMDC->mMaxNumRetries;
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;
+ LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for "
+ << mMDC->mMaxNumRetries << " tries...popping object id " << object->getID() << LL_ENDL;
// XXX Should we bring up a warning dialog??
}
queue.pop();
@@ -395,15 +410,9 @@ 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;
+ LL_INFOS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL;
// LLEventTimer automagically takes care of the lifetime of this object
- new QueueTimer(queue_timer_delay, this);
+ new QueueTimer(mQueueTimerDelay, this);
}
}
@@ -412,9 +421,9 @@ void LLMediaDataClient::stopQueueTimer()
mQueueTimerIsRunning = false;
}
-void LLMediaDataClient::request(LLVOVolume *object, const LLSD &payload)
+void LLMediaDataClient::request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload)
{
- if (NULL == object || ! object->hasMedia()) return;
+ if (object.isNull() || ! object->hasMedia()) return;
// Push the object on the priority queue
enqueue(new Request(getCapabilityName(), payload, object, this));
@@ -437,7 +446,13 @@ void LLMediaDataClient::enqueue(const Request *request)
//
//////////////////////////////////////////////////////////////////////////////////////
-LLMediaDataClient::LLMediaDataClient()
+LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay,
+ F32 retry_timer_delay,
+ U32 max_retries)
+ : mQueueTimerDelay(queue_timer_delay),
+ mRetryTimerDelay(retry_timer_delay),
+ mMaxNumRetries(max_retries),
+ mQueueTimerIsRunning(false)
{
pRequestQueue = new PriorityQueue();
}
@@ -447,12 +462,17 @@ LLMediaDataClient::~LLMediaDataClient()
stopQueueTimer();
// This should clear the queue, and hopefully call all the destructors.
- LL_DEBUGS("LLMediaDataClient") << "destructor: queue: " <<
+ LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClient destructor: queue: " <<
(pRequestQueue->empty() ? "<empty> " : "<not empty> ") << (*pRequestQueue) << LL_ENDL;
delete pRequestQueue;
pRequestQueue = NULL;
}
+bool LLMediaDataClient::isEmpty() const
+{
+ return (NULL == pRequestQueue) ? true : pRequestQueue->empty();
+}
+
//////////////////////////////////////////////////////////////////////////////////////
//
// LLObjectMediaDataClient
@@ -470,7 +490,7 @@ const char *LLObjectMediaDataClient::getCapabilityName() const
return "ObjectMedia";
}
-void LLObjectMediaDataClient::fetchMedia(LLVOVolume *object)
+void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object)
{
LLSD sd_payload;
sd_payload["verb"] = "GET";
@@ -478,18 +498,17 @@ void LLObjectMediaDataClient::fetchMedia(LLVOVolume *object)
request(object, sd_payload);
}
-void LLObjectMediaDataClient::updateMedia(LLVOVolume *object)
+void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *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);
+ int i = 0;
+ int end = object->getMediaDataCount();
+ for ( ; i < end ; ++i)
+ {
+ object_media_data.append(object->getMediaDataLLSD(i));
}
sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data;
@@ -553,7 +572,7 @@ const char *LLObjectMediaNavigateClient::getCapabilityName() const
return "ObjectMediaNavigate";
}
-void LLObjectMediaNavigateClient::navigate(LLVOVolume *object, U8 texture_index, const std::string &url)
+void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url)
{
LLSD sd_payload;
sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
@@ -573,8 +592,10 @@ void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string
}
else {
// bounce the face back
- bounceBack();
LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL;
+ const LLSD &payload = getRequest()->getPayload();
+ // bounce the face back
+ getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
}
}
@@ -591,8 +612,9 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
if (ERROR_PERMISSION_DENIED_CODE == error_code)
{
LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL;
+ const LLSD &payload = getRequest()->getPayload();
// bounce the face back
- bounceBack();
+ getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
}
else {
LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" <<
@@ -605,23 +627,3 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
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(), "", false, true);
- }
-}
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
index 59c4334251..9d0aa0981e 100644
--- a/indra/newview/llmediadataclient.h
+++ b/indra/newview/llmediadataclient.h
@@ -36,12 +36,36 @@
#include "llhttpclient.h"
#include <queue>
#include "llrefcount.h"
+#include "llpointer.h"
#include "lltimer.h"
-// Forward decls
-class LLVOVolume;
-typedef LLPointer<LLVOVolume> ll_vo_volume_ptr_t;
+// Link seam for LLVOVolume
+class LLMediaDataClientObject : public LLRefCount
+{
+public:
+ // Get the number of media data items
+ virtual U8 getMediaDataCount() const = 0;
+ // Get the media data at index, as an LLSD
+ virtual LLSD getMediaDataLLSD(U8 index) const = 0;
+ // Get this object's UUID
+ virtual LLUUID getID() const = 0;
+ // Navigate back to previous URL
+ virtual void mediaNavigateBounceBack(U8 index) = 0;
+ // Does this object have media?
+ virtual bool hasMedia() const = 0;
+ // Update the object's media data to the given array
+ virtual void updateObjectMediaData(LLSD const &media_data_array) = 0;
+ // Return the distance from the object to the avatar
+ virtual F64 getDistanceFromAvatar() const = 0;
+ // Return the total "interest" of the media (on-screen area)
+ virtual F64 getTotalMediaInterest() const = 0;
+ // Return the given cap url
+ virtual std::string getCapabilityUrl(const std::string &name) const = 0;
+
+ // smart pointer
+ typedef LLPointer<LLMediaDataClientObject> ptr_t;
+};
// This object creates a priority queue for requests.
// Abstracts the Cap URL, the request, and the responder
@@ -50,15 +74,23 @@ class LLMediaDataClient : public LLRefCount
public:
LOG_CLASS(LLMediaDataClient);
- const static int QUEUE_TIMER_DELAY = 1; // seconds(s)
- const static int MAX_RETRIES = 4;
+ const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s)
+ const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs
+ const static U32 MAX_RETRIES;// = 4;
// Constructor
- LLMediaDataClient();
+ LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+ F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+ U32 max_retries = MAX_RETRIES);
// Make the request
- void request(LLVOVolume *object, const LLSD &payload);
-
+ void request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload);
+
+ F32 getRetryTimerDelay() const { return mRetryTimerDelay; }
+
+ // Returns true iff the queue is empty
+ bool isEmpty() const;
+
protected:
// Destructor
virtual ~LLMediaDataClient(); // use unref
@@ -73,10 +105,10 @@ protected:
NAVIGATE
};
- Request(const std::string &cap_name, const LLSD& sd_payload, LLVOVolume *obj, LLMediaDataClient *mdc);
+ Request(const std::string &cap_name, const LLSD& sd_payload, LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
const std::string &getCapName() const { return mCapName; }
const LLSD &getPayload() const { return mPayload; }
- LLVOVolume *getObject() const { return mObject; }
+ LLMediaDataClientObject *getObject() const { return mObject; }
U32 getNum() const { return mNum; }
@@ -92,6 +124,9 @@ protected:
// Re-enqueue thyself
void reEnqueue() const;
+ F32 getRetryTimerDelay() const;
+ U32 getMaxNumRetries() const;
+
public:
friend std::ostream& operator<<(std::ostream &s, const Request &q);
@@ -101,7 +136,7 @@ protected:
private:
std::string mCapName;
LLSD mPayload;
- ll_vo_volume_ptr_t mObject;
+ LLMediaDataClientObject::ptr_t mObject;
// Simple tracking
const U32 mNum;
static U32 sNum;
@@ -115,8 +150,6 @@ protected:
// 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
@@ -163,9 +196,10 @@ private:
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);
+ static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj);
};
+ // PriorityQueue
class PriorityQueue : public std::priority_queue<
request_ptr_t,
std::vector<request_ptr_t>,
@@ -193,6 +227,10 @@ private:
void startQueueTimer();
void stopQueueTimer();
void setIsRunning(bool val) { mQueueTimerIsRunning = val; }
+
+ const F32 mQueueTimerDelay;
+ const F32 mRetryTimerDelay;
+ const U32 mMaxNumRetries;
bool mQueueTimerIsRunning;
@@ -204,11 +242,15 @@ private:
class LLObjectMediaDataClient : public LLMediaDataClient
{
public:
- LLObjectMediaDataClient() {}
+ LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+ F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+ U32 max_retries = MAX_RETRIES)
+ : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
+ {}
~LLObjectMediaDataClient() {}
- void fetchMedia(LLVOVolume *object);
- void updateMedia(LLVOVolume *object);
+ void fetchMedia(LLMediaDataClientObject *object);
+ void updateMedia(LLMediaDataClientObject *object);
protected:
// Subclasses must override this factory method to return a new responder
@@ -230,14 +272,18 @@ protected:
// MediaDataResponder specific for the ObjectMediaNavigate cap
class LLObjectMediaNavigateClient : public LLMediaDataClient
{
+public:
// NOTE: from llmediaservice.h
static const int ERROR_PERMISSION_DENIED_CODE = 8002;
-public:
- LLObjectMediaNavigateClient() {}
+ LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+ F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+ U32 max_retries = MAX_RETRIES)
+ : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
+ {}
~LLObjectMediaNavigateClient() {}
- void navigate(LLVOVolume *object, U8 texture_index, const std::string &url);
+ void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url);
protected:
// Subclasses must override this factory method to return a new responder
@@ -254,7 +300,7 @@ protected:
virtual void error(U32 status, const std::string& reason);
virtual void result(const LLSD &content);
private:
- void bounceBack();
+ void mediaNavigateBounceBack();
};
};
diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp
index 295415cb2d..a33d9604fe 100644
--- a/indra/newview/llpanelmediasettingsgeneral.cpp
+++ b/indra/newview/llpanelmediasettingsgeneral.cpp
@@ -385,8 +385,7 @@ void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in )
fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = mAutoScale->getValue();
fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = mAutoZoom->getValue();
fill_me_in[LLMediaEntry::CONTROLS_KEY] = mControls->getCurrentIndex();
- // XXX Don't send current URL!
- //fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue();
+ fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue();
fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = mHeightPixels->getValue();
fill_me_in[LLMediaEntry::HOME_URL_KEY] = mHomeURL->getValue();
fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = mFirstClick->getValue();
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index bac87b70be..3a503f22a0 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -588,6 +588,7 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
mHasFocus(false),
mPriority(LLPluginClassMedia::PRIORITY_UNLOADED),
mDoNavigateOnLoad(false),
+ mDoNavigateOnLoadRediscoverType(false),
mDoNavigateOnLoadServerRequest(false),
mMediaSourceFailedInit(false),
mIsUpdated(false)
@@ -665,7 +666,7 @@ void LLViewerMediaImpl::createMediaSource()
{
if(! mMediaURL.empty())
{
- navigateTo(mMediaURL, mMimeType, false, mDoNavigateOnLoadServerRequest);
+ navigateTo(mMediaURL, mMimeType, mDoNavigateOnLoadRediscoverType, mDoNavigateOnLoadServerRequest);
}
else if(! mMimeType.empty())
{
@@ -1010,14 +1011,7 @@ BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask)
//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::navigateHome()
{
- mMediaURL = mHomeURL;
- mDoNavigateOnLoad = !mMediaURL.empty();
- mDoNavigateOnLoadServerRequest = false;
-
- if(mMediaSource)
- {
- mMediaSource->loadURI( mHomeURL );
- }
+ navigateTo(mHomeURL, "", true, false);
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1032,12 +1026,16 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
setNavState(MEDIANAVSTATE_NONE);
}
- // Always set the current URL.
+ // Always set the current URL and MIME type.
mMediaURL = url;
+ mMimeType = mime_type;
// If the current URL is not null, make the instance do a navigate on load.
mDoNavigateOnLoad = !mMediaURL.empty();
+ // if mime type discovery was requested, we'll need to do it when the media loads
+ mDoNavigateOnLoadRediscoverType = rediscover_type;
+
// and if this was a server request, the navigate on load will also need to be one.
mDoNavigateOnLoadServerRequest = server_request;
@@ -1048,6 +1046,21 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi
return;
}
+
+ // If the caller has specified a non-empty MIME type, look that up in our MIME types list.
+ // If we have a plugin for that MIME type, use that instead of attempting auto-discovery.
+ // This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type
+ // but the parcel owner has correctly set the MIME type in the parcel media settings.
+
+ if(!mMimeType.empty() && (mMimeType != "none/none"))
+ {
+ std::string plugin_basename = LLMIMETypes::implType(mMimeType);
+ if(!plugin_basename.empty())
+ {
+ // We have a plugin for this mime type
+ rediscover_type = false;
+ }
+ }
if(rediscover_type)
{
@@ -1446,7 +1459,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
{
LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL;
- setNavState(MEDIANAVSTATE_NONE);
}
break;
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index d534ef97b9..37aabcf2d6 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -278,6 +278,7 @@ public:
bool mHasFocus;
LLPluginClassMedia::EPriority mPriority;
bool mDoNavigateOnLoad;
+ bool mDoNavigateOnLoadRediscoverType;
bool mDoNavigateOnLoadServerRequest;
bool mMediaSourceFailedInit;
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index f9377ab37b..1b1b7cedb1 100644
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -304,7 +304,11 @@ BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks)
BOOL retval = FALSE;
if(mFocus.notNull() && mMediaImpl.notNull() && mMediaImpl->hasMedia())
{
- mMediaImpl->getMediaPlugin()->scrollEvent(x, y, clicks);
+ // the scrollEvent() API's x and y are not the same as handleScrollWheel's x and y.
+ // The latter is the position of the mouse at the time of the event
+ // The former is the 'scroll amount' in x and y, respectively.
+ // All we have for 'scroll amount' here is 'clicks', and no mask.
+ mMediaImpl->getMediaPlugin()->scrollEvent(0, clicks, /*mask*/0);
retval = TRUE;
}
return retval;
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index 6fba909983..9bcdcbf9ad 100644
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -226,11 +226,13 @@ void LLViewerParcelMedia::play(LLParcel* parcel)
media_height,
media_auto_scale,
media_loop);
- sMediaImpl->navigateTo(media_url);
+ sMediaImpl->navigateTo(media_url, mime_type, true);
}
}
else
{
+ LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL;
+
// There is no media impl, make a new one
sMediaImpl = LLViewerMedia::newMediaImpl(
placeholder_texture_id,
@@ -238,7 +240,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel)
media_height,
media_auto_scale,
media_loop);
- sMediaImpl->navigateTo(media_url);
+ sMediaImpl->navigateTo(media_url, mime_type, true);
}
LLFirstUse::useMedia();
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 428de078de..1704f63376 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -91,6 +91,57 @@ LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient =
static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
+// Implementation class of LLMediaDataClientObject. See llmediadataclient.h
+class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
+{
+public:
+ LLMediaDataClientObjectImpl(LLVOVolume *obj) : mObject(obj) {}
+ LLMediaDataClientObjectImpl() { mObject = NULL; }
+
+ virtual U8 getMediaDataCount() const
+ { return mObject->getNumTEs(); }
+
+ virtual LLSD getMediaDataLLSD(U8 index) const
+ {
+ LLSD result;
+ LLTextureEntry *te = mObject->getTE(index);
+ if (NULL != te)
+ {
+ llassert((te->getMediaData() != NULL) == te->hasMedia());
+ if (te->getMediaData() != NULL)
+ {
+ result = te->getMediaData()->asLLSD();
+ }
+ }
+ return result;
+ }
+
+ virtual LLUUID getID() const
+ { return mObject->getID(); }
+
+ virtual void mediaNavigateBounceBack(U8 index)
+ { mObject->mediaNavigateBounceBack(index); }
+
+ virtual bool hasMedia() const
+ { return mObject->hasMedia(); }
+
+ virtual void updateObjectMediaData(LLSD const &data)
+ { mObject->updateObjectMediaData(data); }
+
+ virtual F64 getDistanceFromAvatar() const
+ { return mObject->getRenderPosition().length(); }
+
+ virtual F64 getTotalMediaInterest() const
+ { return mObject->getTotalMediaInterest(); }
+
+ virtual std::string getCapabilityUrl(const std::string &name) const
+ { return mObject->getRegion()->getCapability(name); }
+
+private:
+ LLPointer<LLVOVolume> mObject;
+};
+
+
LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
: LLViewerObject(id, pcode, regionp),
mVolumeImpl(NULL)
@@ -134,8 +185,12 @@ LLVOVolume::~LLVOVolume()
// static
void LLVOVolume::initClass()
{
- sObjectMediaClient = new LLObjectMediaDataClient();
- sObjectMediaNavigateClient = new LLObjectMediaNavigateClient();
+ // gSavedSettings better be around
+ const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay");
+ const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay");
+ const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries");
+ sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries);
+ sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay, max_retries);
}
// static
@@ -1634,7 +1689,7 @@ bool LLVOVolume::hasMedia() const
void LLVOVolume::requestMediaDataUpdate()
{
- sObjectMediaClient->fetchMedia(this);
+ sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this));
}
void LLVOVolume::cleanUpMediaImpls()
@@ -1713,6 +1768,72 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m
// << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl;
}
+void LLVOVolume::mediaNavigateBounceBack(U8 texture_index)
+{
+ // Find the media entry for this navigate
+ const LLMediaEntry* mep = NULL;
+ viewer_media_t impl = getMediaImpl(texture_index);
+ LLTextureEntry *te = getTE(texture_index);
+ if(te)
+ {
+ mep = te->getMediaData();
+ }
+
+ if (mep && impl)
+ {
+ std::string url = mep->getCurrentURL();
+ if (url.empty())
+ {
+ url = mep->getHomeURL();
+ }
+ if (! url.empty())
+ {
+ LL_INFOS("LLMediaDataClient") << "bouncing back to URL: " << url << LL_ENDL;
+ impl->navigateTo(url, "", false, true);
+ }
+ }
+}
+
+bool LLVOVolume::hasNavigatePermission(const LLMediaEntry* media_entry)
+{
+ // NOTE: This logic duplicates the logic in the server (in particular, in llmediaservice.cpp).
+ if (NULL == media_entry ) return false; // XXX should we assert here?
+
+ // The agent has permissions to navigate if:
+ // - agent has edit permissions, or
+ // - world permissions are on, or
+ // - group permissions are on, and agent_id is in the group, or
+ // - agent permissions are on, and agent_id is the owner
+
+ if (permModify())
+ {
+ return true;
+ }
+
+ U8 media_perms = media_entry->getPermsInteract();
+
+ // World permissions
+ if (0 != (media_perms & LLMediaEntry::PERM_ANYONE))
+ {
+ return true;
+ }
+
+ // Group permissions
+ else if (0 != (media_perms & LLMediaEntry::PERM_GROUP) && permGroupOwner())
+ {
+ return true;
+ }
+
+ // Owner permissions
+ else if (0 != (media_perms & LLMediaEntry::PERM_OWNER) && permYouOwner())
+ {
+ return true;
+ }
+
+ return false;
+
+}
+
void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event)
{
switch(event)
@@ -1746,6 +1867,10 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
{
block_navigation = true;
}
+ if (!block_navigation && !hasNavigatePermission(mep))
+ {
+ block_navigation = true;
+ }
}
else
{
@@ -1757,15 +1882,14 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
llinfos << "blocking navigate to URI " << new_location << llendl;
// "bounce back" to the current URL from the media entry
- // NOTE: the only way block_navigation can be true is if we found the media entry, so we're guaranteed here that mep is not NULL.
- impl->navigateTo(mep->getCurrentURL());
+ mediaNavigateBounceBack(face_index);
}
else
{
llinfos << "broadcasting navigate with URI " << new_location << llendl;
- sObjectMediaNavigateClient->navigate(this, face_index, new_location);
+ sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this), face_index, new_location);
}
}
break;
@@ -1791,7 +1915,7 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
void LLVOVolume::sendMediaDataUpdate()
{
- sObjectMediaClient->updateMedia(this);
+ sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this));
}
void LLVOVolume::removeMediaImpl(S32 texture_index)
@@ -1884,6 +2008,22 @@ viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const
return NULL;
}
+F64 LLVOVolume::getTotalMediaInterest() const
+{
+ F64 interest = (F64)0.0;
+ int i = 0;
+ const int end = getNumTEs();
+ for ( ; i < end; ++i)
+ {
+ const viewer_media_t &impl = getMediaImpl(i);
+ if (!impl.isNull())
+ {
+ interest += impl->getInterest();
+ }
+ }
+ return interest;
+}
+
S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id)
{
S32 end = (S32)mMediaImplList.size() ;
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 250c3ed917..90dfa2204b 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -233,7 +233,18 @@ public:
BOOL canBeFlexible() const;
BOOL setIsFlexible(BOOL is_flexible);
- void updateObjectMediaData(const LLSD &media_data_duples);
+ // Functions that deal with media, or media navigation
+
+ // Update this object's media data with the given media data array
+ // (typically this is only called upon a response from a server request)
+ void updateObjectMediaData(const LLSD &media_data_array);
+
+ // Bounce back media at the given index to its current URL (or home URL, if current URL is empty)
+ void mediaNavigateBounceBack(U8 texture_index);
+
+ // Returns whether or not this object has permission to navigate the given media entry
+ bool hasNavigatePermission(const LLMediaEntry* media_entry);
+
void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event);
// Sync the given media data with the impl and the given te
@@ -244,6 +255,7 @@ public:
viewer_media_t getMediaImpl(U8 face_id) const;
S32 getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id);
+ F64 getTotalMediaInterest() const;
bool hasMedia() const;
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
new file mode 100644
index 0000000000..a884ed0265
--- /dev/null
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -0,0 +1,483 @@
+/**
+ * @file llmediadataclient_test.cpp
+ * @brief LLMediaDatClient tests
+ *
+ * $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 <iostream>
+#include "../test/lltut.h"
+
+#include "llsdserialize.h"
+#include "llsdutil.h"
+#include "llerrorcontrol.h"
+#include "llhttpstatuscodes.h"
+
+#include "../llmediadataclient.h"
+#include "../llvovolume.h"
+
+#include "../../llprimitive/llmediaentry.cpp"
+#include "../../llprimitive/lltextureentry.cpp"
+#include "../../llmessage/tests/llcurl_stub.cpp"
+
+#include <boost/lexical_cast.hpp>
+
+#define VALID_OBJECT_ID "3607d5c4-644b-4a8a-871a-8b78471af2a2"
+#define VALID_OBJECT_ID_1 "11111111-1111-1111-1111-111111111111"
+#define VALID_OBJECT_ID_2 "22222222-2222-2222-2222-222222222222"
+#define VALID_OBJECT_ID_3 "33333333-3333-3333-3333-333333333333"
+#define VALID_OBJECT_ID_4 "44444444-4444-4444-4444-444444444444"
+
+#define FAKE_OBJECT_MEDIA_CAP_URL "foo_ObjectMedia"
+#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL "foo_ObjectMediaNavigate"
+#define FAKE_OBJECT_MEDIA_CAP_URL_503 "foo_ObjectMedia_503"
+#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR "foo_ObjectMediaNavigate_ERROR"
+
+#define MEDIA_DATA "\
+<array> \
+<string>foo</string> \
+<string>bar</string> \
+<string>baz</string> \
+</array>"
+
+#define _DATA_URLS(ID,DIST,INT,URL1,URL2) " \
+<llsd> \
+ <map> \
+ <key>uuid</key> \
+ <string>" ID "</string> \
+ <key>distance</key> \
+ <real>" DIST "</real> \
+ <key>interest</key> \
+ <real>" INT "</real> \
+ <key>cap_urls</key> \
+ <map> \
+ <key>ObjectMedia</key> \
+ <string>" URL1 "</string> \
+ <key>ObjectMediaNavigate</key> \
+ <string>" URL2 "</string> \
+ </map> \
+ <key>media_data</key> \
+ " MEDIA_DATA " \
+ </map> \
+</llsd>"
+
+#define _DATA(ID,DIST,INT) _DATA_URLS(ID,DIST,INT,FAKE_OBJECT_MEDIA_CAP_URL,FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL)
+
+const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","1.0");
+
+#define STR(I) boost::lexical_cast<std::string>(I)
+
+#define LOG_TEST(N) LL_DEBUGS("LLMediaDataClient") << "\n" << \
+"================================================================================\n" << \
+"===================================== TEST " #N " ===================================\n" << \
+"================================================================================\n" << LL_ENDL;
+
+LLSD *gPostRecords = NULL;
+
+// stubs:
+void LLHTTPClient::post(
+ const std::string& url,
+ const LLSD& body,
+ LLHTTPClient::ResponderPtr responder,
+ const LLSD& headers,
+ const F32 timeout)
+{
+ LLSD record;
+ record["url"] = url;
+ record["body"] = body;
+ record["headers"] = headers;
+ record["timeout"] = timeout;
+ gPostRecords->append(record);
+
+ // Magic URL that triggers a 503:
+ if ( url == FAKE_OBJECT_MEDIA_CAP_URL_503 )
+ {
+ responder->error(HTTP_SERVICE_UNAVAILABLE, "fake reason");
+ }
+ else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR)
+ {
+ LLSD result;
+ LLSD error;
+ error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE;
+ result["error"] = error;
+ responder->result(result);
+ }
+ else {
+ responder->result(LLSD());
+ }
+}
+
+const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
+
+class LLMediaDataClientObjectTest : public LLMediaDataClientObject
+{
+public:
+ LLMediaDataClientObjectTest(const char *data)
+ {
+ std::istringstream d(data);
+ LLSDSerialize::fromXML(mRep, d);
+ mNumBounceBacks = 0;
+
+ // std::cout << ll_pretty_print_sd(mRep) << std::endl;
+ // std::cout << "ID: " << getID() << std::endl;
+ }
+ LLMediaDataClientObjectTest(const LLSD &rep)
+ : mRep(rep), mNumBounceBacks(0) {}
+ ~LLMediaDataClientObjectTest()
+ { LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClientObjectTest" << LL_ENDL; }
+
+ virtual U8 getMediaDataCount() const
+ { return mRep["media_data"].size(); }
+ virtual LLSD getMediaDataLLSD(U8 index) const
+ { return mRep["media_data"][(LLSD::Integer)index]; }
+ virtual LLUUID getID() const
+ { return mRep["uuid"]; }
+ virtual void mediaNavigateBounceBack(U8 index)
+ {
+ mNumBounceBacks++;
+ }
+
+ virtual bool hasMedia() const
+ { return mRep.has("media_data"); }
+
+ virtual void updateObjectMediaData(LLSD const &media_data_array)
+ { mRep["media_data"] = media_data_array; }
+
+ virtual F64 getDistanceFromAvatar() const
+ { return (LLSD::Real)mRep["distance"]; }
+
+ virtual F64 getTotalMediaInterest() const
+ { return (LLSD::Real)mRep["interest"]; }
+
+ virtual std::string getCapabilityUrl(const std::string &name) const
+ { return mRep["cap_urls"][name]; }
+
+ int getNumBounceBacks() const
+ { return mNumBounceBacks; }
+
+private:
+ LLSD mRep;
+ int mNumBounceBacks;
+};
+
+
+namespace tut
+{
+ struct mediadataclient
+ {
+ mediadataclient() {
+ gPostRecords = &mLLSD;
+
+// LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+// LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
+// LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
+ }
+ LLSD mLLSD;
+ };
+
+ typedef test_group<mediadataclient> mediadataclient_t;
+ typedef mediadataclient_t::object mediadataclient_object_t;
+ tut::mediadataclient_t tut_mediadataclient("mediadataclient");
+
+ void ensure(const std::string &msg, int value, int expected)
+ {
+ std::string m = msg;
+ m += " value: " + STR(value);
+ m += ", expected: " + STR(expected);
+ ensure(m, value == expected);
+ }
+
+ void ensure(const std::string &msg, const std::string & value, const std::string & expected)
+ {
+ std::string m = msg;
+ m += " value: " + value;
+ m += ", expected: " + expected;
+ ensure(m, value == expected);
+ }
+
+ void ensure(const std::string &msg, const LLUUID & value, const LLUUID & expected)
+ {
+ std::string m = msg;
+ m += " value: " + value.asString();
+ m += ", expected: " + expected.asString();
+ ensure(m, value == expected);
+ }
+
+ void ensure_llsd(const std::string &msg, const LLSD & value, const char *expected)
+ {
+ LLSD expected_llsd;
+ std::istringstream e(expected);
+ LLSDSerialize::fromXML(expected_llsd, e);
+
+ std::string value_str = ll_pretty_print_sd(value);
+ std::string expected_str = ll_pretty_print_sd(expected_llsd);
+ std::string m = msg;
+ m += " value: " + value_str;
+ m += ", expected: " + expected_str;
+ ensure(m, value_str == expected_str);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<1>()
+ {
+ //
+ // Test fetchMedia()
+ //
+ LOG_TEST(1);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ int num_refs_start = o->getNumRefs();
+ {
+ // queue time w/ no delay ensures that LLEventTimer::updateClass() will hit the tick()
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);
+ mdc->fetchMedia(o);
+
+ // Make sure no posts happened yet...
+ ensure("post records", gPostRecords->size(), 0);
+
+ LLEventTimer::updateClass();
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("post GET", (*gPostRecords)[0]["body"]["verb"], "GET");
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ // Make sure everyone's destroyed properly
+ ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<2>()
+ {
+ //
+ // Test updateMedia()
+ //
+ LOG_TEST(2);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ {
+ // queue time w/ no delay ensures that LLEventTimer::updateClass() will hit the tick()
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);
+ mdc->updateMedia(o);
+ ensure("post records", gPostRecords->size(), 0);
+ LLEventTimer::updateClass();
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("post UPDATE", (*gPostRecords)[0]["body"]["verb"], "UPDATE");
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure_llsd("post data llsd", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_MEDIA_DATA_KEY],
+ "<llsd>" MEDIA_DATA "</llsd>");
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<3>()
+ {
+ //
+ // Test navigate()
+ //
+ LOG_TEST(3);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ {
+ LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(0,0,4);
+ const char *TEST_URL = "http://example.com";
+ mdc->navigate(o, 0, TEST_URL);
+ ensure("post records", gPostRecords->size(), 0);
+ LLEventTimer::updateClass();
+
+ // ensure no bounce back
+ ensure("bounce back", dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(), 0);
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL);
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
+ ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<4>()
+ {
+ //
+ // Test queue ordering
+ //
+ LOG_TEST(4);
+
+ LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_1,"3.0","1.0"));
+ LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_2,"1.0","1.0"));
+ LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_3,"2.0","1.0"));
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);
+ const char *ORDERED_OBJECT_IDS[] = { VALID_OBJECT_ID_2, VALID_OBJECT_ID_3, VALID_OBJECT_ID_1 };
+ mdc->fetchMedia(o1);
+ mdc->fetchMedia(o2);
+ mdc->fetchMedia(o3);
+
+ // Make sure no posts happened yet...
+ ensure("post records", gPostRecords->size(), 0);
+
+ // tick 3 times...
+ LLEventTimer::updateClass();
+ ensure("post records", gPostRecords->size(), 1);
+ LLEventTimer::updateClass();
+ ensure("post records", gPostRecords->size(), 2);
+ LLEventTimer::updateClass();
+ ensure("post records", gPostRecords->size(), 3);
+
+ for( int i=0; i < 3; i++ )
+ {
+ ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
+ ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(),
+ LLUUID(ORDERED_OBJECT_IDS[i]));
+ }
+
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("refcount of o1", o1->getNumRefs(), 1);
+ ensure("refcount of o2", o2->getNumRefs(), 1);
+ ensure("refcount of o3", o3->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<5>()
+ {
+ //
+ // Test fetchMedia() getting a 503 error
+ //
+ LOG_TEST(5);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
+ _DATA_URLS(VALID_OBJECT_ID,
+ "1.0",
+ "1.0",
+ FAKE_OBJECT_MEDIA_CAP_URL_503,
+ FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL));
+ int num_refs_start = o->getNumRefs();
+ {
+ const int NUM_RETRIES = 5;
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,NUM_RETRIES);
+
+ // This should generate a retry
+ mdc->fetchMedia(o);
+
+ // Make sure no posts happened yet...
+ ensure("post records before", gPostRecords->size(), 0);
+
+ // Once, causes retry
+ // Second, fires retry timer
+ // Third, fires queue timer again
+ for (int i=0; i<NUM_RETRIES; ++i)
+ {
+ LLEventTimer::updateClass();
+ ensure("post records " + STR(i), gPostRecords->size(), i+1);
+ LLEventTimer::updateClass();
+ }
+
+ // Do some extre pumps to make sure no other timer work occurs.
+ LLEventTimer::updateClass();
+ LLEventTimer::updateClass();
+ LLEventTimer::updateClass();
+
+ // Make sure there were 2 posts
+ ensure("post records after", gPostRecords->size(), NUM_RETRIES);
+ for (int i=0; i<NUM_RETRIES; ++i)
+ {
+ ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL_503);
+ ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
+ ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ }
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ // Make sure everyone's destroyed properly
+ ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+ }
+
+ template<> template<>
+ void mediadataclient_object_t::test<6>()
+ {
+ //
+ // Test navigate() with a bounce back
+ //
+ LOG_TEST(6);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
+ _DATA_URLS(VALID_OBJECT_ID,
+ "1.0",
+ "1.0",
+ FAKE_OBJECT_MEDIA_CAP_URL,
+ FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR));
+ {
+ LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(0,0,4);
+ const char *TEST_URL = "http://example.com";
+ mdc->navigate(o, 0, TEST_URL);
+ ensure("post records", gPostRecords->size(), 0);
+ LLEventTimer::updateClass();
+
+ // ensure bounce back
+ ensure("bounce back",
+ dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(),
+ 1);
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR);
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
+ ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+
+}