Merge media back into viewer 2-0

meow-7.2.2
skolb 2009-12-11 09:07:39 -08:00
commit f0da8a7420
20 changed files with 1919 additions and 508 deletions

View File

@ -1,6 +1,6 @@
/**
* @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$
@ -96,6 +96,10 @@ std::string LLPluginSharedMemory::createName(void)
return newname.str();
}
/**
* @brief LLPluginSharedMemoryImpl is the platform-dependent implementation of LLPluginSharedMemory. TODO:DOC is this necessary/sufficient? kinda obvious.
*
*/
class LLPluginSharedMemoryPlatformImpl
{
public:
@ -112,6 +116,9 @@ public:
};
/**
* Constructor. Creates a shared memory segment.
*/
LLPluginSharedMemory::LLPluginSharedMemory()
{
mSize = 0;
@ -121,6 +128,9 @@ LLPluginSharedMemory::LLPluginSharedMemory()
mImpl = new LLPluginSharedMemoryPlatformImpl;
}
/**
* Destructor. Uses destroy() and detach() to ensure shared memory segment is cleaned up.
*/
LLPluginSharedMemory::~LLPluginSharedMemory()
{
if(mNeedsDestroy)

View File

@ -1,6 +1,5 @@
/**
* @file llpluginsharedmemory.h
* @brief LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewergpl$
@ -36,6 +35,10 @@
class LLPluginSharedMemoryPlatformImpl;
/**
* @brief LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API.
*
*/
class LLPluginSharedMemory
{
LOG_CLASS(LLPluginSharedMemory);
@ -46,16 +49,62 @@ public:
// Parent will use create/destroy, child will use attach/detach.
// Message transactions will ensure child attaches after parent creates and detaches before parent destroys.
// create() implicitly creates a name for the segment which is guaranteed to be unique on the host at the current time.
/**
* Creates a shared memory segment, with a name which is guaranteed to be unique on the host at the current time. Used by parent.
* Message transactions will (? TODO:DOC - should? must?) ensure child attaches after parent creates and detaches before parent destroys.
*
* @param[in] size Shared memory size in TODO:DOC units = bytes?.
*
* @return False for failure, true for success.
*/
bool create(size_t size);
/**
* Destroys a shared memory segment. Used by parent.
* Message transactions will (? TODO:DOC - should? must?) ensure child attaches after parent creates and detaches before parent destroys.
*
* @return True. TODO:DOC - always returns true. Is this the intended behavior?
*/
bool destroy(void);
/**
* Creates and attaches a name to a shared memory segment. TODO:DOC what's the difference between attach() and create()?
*
* @param[in] name Name to attach to memory segment
* @param[in] size Size of memory segment TODO:DOC in bytes?
*
* @return False on failure, true otherwise.
*/
bool attach(const std::string &name, size_t size);
/**
* Detaches shared memory segment.
*
* @return False on failure, true otherwise.
*/
bool detach(void);
/**
* Checks if shared memory is mapped to a non-null address.
*
* @return True if memory address is non-null, false otherwise.
*/
bool isMapped(void) const { return (mMappedAddress != NULL); };
/**
* Get pointer to shared memory.
*
* @return Pointer to shared memory.
*/
void *getMappedAddress(void) const { return mMappedAddress; };
/**
* Get size of shared memory.
*
* @return Size of shared memory in bytes. TODO:DOC are bytes the correct unit?
*/
size_t getSize(void) const { return mSize; };
/**
* Get name of shared memory.
*
* @return Name of shared memory.
*/
std::string getName() const { return mName; };
private:

View File

@ -5514,6 +5514,28 @@
<string>F32</string>
<key>Value</key>
<real>5.0</real>
</map>
<key>PrimMediaMaxSortedQueueSize</key>
<map>
<key>Comment</key>
<string>Maximum number of objects the viewer will load media for initially</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>100000</integer>
</map>
<key>PrimMediaMaxRoundRobinQueueSize</key>
<map>
<key>Comment</key>
<string>Maximum number of objects the viewer will continuously update media for</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>100000</integer>
</map>
<key>ProbeHardwareOnStartup</key>
<map>

View File

@ -746,7 +746,15 @@ bool LLAppViewer::init()
LLViewerJointMesh::updateVectorize();
// load MIME type -> media impl mappings
LLMIMETypes::parseMIMETypes( std::string("mime_types.xml") );
std::string mime_types_name;
#if LL_DARWIN
mime_types_name = "mime_types_mac.xml";
#elif LL_LINUX
mime_types_name = "mime_types_linux.xml";
#else
mime_types_name = "mime_types.xml";
#endif
LLMIMETypes::parseMIMETypes( mime_types_name );
// Copy settings to globals. *TODO: Remove or move to appropriage class initializers
settings_to_globals();

View File

@ -1080,7 +1080,7 @@ void LLFloaterTools::getMediaState()
{
LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection();
LLViewerObject* first_object = selected_objects->getFirstObject();
LLLineEditor* media_info = getChild<LLLineEditor>("media_info");
LLTextBox* media_info = getChild<LLTextBox>("media_info");
if( !(first_object
&& first_object->getPCode() == LL_PCODE_VOLUME
@ -1088,12 +1088,6 @@ void LLFloaterTools::getMediaState()
))
{
childSetEnabled("Add_Media", FALSE);
/* childSetEnabled("media_tex", FALSE);
childSetEnabled("add_media", FALSE);
childSetEnabled("delete_media", FALSE);
childSetEnabled("edit_media", FALSE);
childSetEnabled("media_info", FALSE);
media_info->setEnabled(FALSE);*/
media_info->clear();
clearMediaSettings();
return;
@ -1105,13 +1099,6 @@ void LLFloaterTools::getMediaState()
if(!has_media_capability)
{
childSetEnabled("Add_Media", FALSE);
/* childSetEnabled("media_tex", FALSE);
childSetEnabled("add_media", FALSE);
childSetEnabled("delete_media", FALSE);
childSetEnabled("edit_media", FALSE);
childSetEnabled("media_info", FALSE);
media_info->setEnabled(FALSE);
media_info->clear();*/
LL_WARNS("LLFloaterTools: media") << "Media not enabled (no capability) in this region!" << LL_ENDL;
clearMediaSettings();
return;
@ -1233,7 +1220,6 @@ void LLFloaterTools::getMediaState()
childSetEnabled( "edit_media", bool_has_media & editable );
childSetEnabled( "delete_media", bool_has_media & editable );
childSetEnabled( "add_media", ( ! bool_has_media ) & editable );
media_info->setEnabled(false);
// TODO: display a list of all media on the face - use 'identical' flag
}
else // not all face has media but at least one does.
@ -1260,8 +1246,6 @@ void LLFloaterTools::getMediaState()
}
}
media_info->setEnabled(false);
media_info->setTentative(true);
childSetEnabled("media_tex", TRUE);
childSetEnabled( "edit_media", TRUE);
childSetEnabled( "delete_media", TRUE);
@ -1392,7 +1376,7 @@ void LLFloaterTools::updateMediaTitle()
if ( ! media_title.empty() )
{
// update the UI widget
LLLineEditor* media_title_field = getChild<LLLineEditor>("media_info");
LLTextBox* media_title_field = getChild<LLTextBox>("media_info");
if ( media_title_field )
{
media_title_field->setText( media_title );

View File

@ -61,6 +61,408 @@
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;
const U32 LLMediaDataClient::MAX_SORTED_QUEUE_SIZE = 10000;
const U32 LLMediaDataClient::MAX_ROUND_ROBIN_QUEUE_SIZE = 10000;
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient
//
//////////////////////////////////////////////////////////////////////////////////////
LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay,
F32 retry_timer_delay,
U32 max_retries,
U32 max_sorted_queue_size,
U32 max_round_robin_queue_size)
: mQueueTimerDelay(queue_timer_delay),
mRetryTimerDelay(retry_timer_delay),
mMaxNumRetries(max_retries),
mMaxSortedQueueSize(max_sorted_queue_size),
mMaxRoundRobinQueueSize(max_round_robin_queue_size),
mQueueTimerIsRunning(false),
mCurrentQueueIsTheSortedQueue(true)
{
}
LLMediaDataClient::~LLMediaDataClient()
{
stopQueueTimer();
// This should clear the queue, and hopefully call all the destructors.
LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClient destructor: queue: " <<
(isEmpty() ? "<empty> " : "<not empty> ") << LL_ENDL;
mSortedQueue.clear();
mRoundRobinQueue.clear();
}
bool LLMediaDataClient::isEmpty() const
{
return mSortedQueue.empty() && mRoundRobinQueue.empty();
}
bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object)
{
return (LLMediaDataClient::findOrRemove(mSortedQueue, object, false/*remove*/, LLMediaDataClient::Request::ANY).notNull()
|| (LLMediaDataClient::findOrRemove(mRoundRobinQueue, object, false/*remove*/, LLMediaDataClient::Request::ANY).notNull()));
}
bool LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object)
{
bool removedFromSortedQueue = LLMediaDataClient::findOrRemove(mSortedQueue, object, true/*remove*/, LLMediaDataClient::Request::ANY).notNull();
bool removedFromRoundRobinQueue = LLMediaDataClient::findOrRemove(mRoundRobinQueue, object, true/*remove*/, LLMediaDataClient::Request::ANY).notNull();
return removedFromSortedQueue || removedFromRoundRobinQueue;
}
//static
LLMediaDataClient::request_ptr_t LLMediaDataClient::findOrRemove(request_queue_t &queue, const LLMediaDataClientObject::ptr_t &obj, bool remove, LLMediaDataClient::Request::Type type)
{
request_ptr_t result;
request_queue_t::iterator iter = queue.begin();
request_queue_t::iterator end = queue.end();
while (iter != end)
{
if (obj->getID() == (*iter)->getObject()->getID() && (type == LLMediaDataClient::Request::ANY || type == (*iter)->getType()))
{
result = *iter;
if (remove) queue.erase(iter);
break;
}
iter++;
}
return result;
}
void LLMediaDataClient::request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload)
{
if (object.isNull() || ! object->hasMedia()) return;
// Push the object on the queue
enqueue(new Request(getCapabilityName(), payload, object, this));
}
void LLMediaDataClient::enqueue(const Request *request)
{
if (request->isNew())
{
// Add to sorted queue
if (LLMediaDataClient::findOrRemove(mSortedQueue, request->getObject(), true/*remove*/, request->getType()).notNull())
{
LL_DEBUGS("LLMediaDataClient") << "REMOVING OLD request for " << *request << " ALREADY THERE!" << LL_ENDL;
}
LL_DEBUGS("LLMediaDataClient") << "Queuing SORTED request for " << *request << LL_ENDL;
// Sadly, we have to const-cast because items put into the queue are not const
mSortedQueue.push_back(const_cast<LLMediaDataClient::Request*>(request));
LL_DEBUGS("LLMediaDataClient") << "SORTED queue:" << mSortedQueue << LL_ENDL;
}
else {
if (mRoundRobinQueue.size() > mMaxRoundRobinQueueSize)
{
LL_INFOS_ONCE("LLMediaDataClient") << "RR QUEUE MAXED OUT!!!" << LL_ENDL;
LL_DEBUGS("LLMediaDataClient") << "Not queuing " << *request << LL_ENDL;
return;
}
// ROUND ROBIN: if it is there, and it is a GET request, leave it. If not, put at front!
request_ptr_t existing_request;
if (request->getType() == Request::GET)
{
existing_request = LLMediaDataClient::findOrRemove(mRoundRobinQueue, request->getObject(), false/*remove*/, request->getType());
}
if (existing_request.isNull())
{
LL_DEBUGS("LLMediaDataClient") << "Queuing RR request for " << *request << LL_ENDL;
// Push the request on the pending queue
// Sadly, we have to const-cast because items put into the queue are not const
mRoundRobinQueue.push_front(const_cast<LLMediaDataClient::Request*>(request));
LL_DEBUGS("LLMediaDataClient") << "RR queue:" << mRoundRobinQueue << LL_ENDL;
}
else
{
LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL;
existing_request->markSent(false);
}
}
// Start the timer if not already running
startQueueTimer();
}
void LLMediaDataClient::startQueueTimer()
{
if (! mQueueTimerIsRunning)
{
LL_DEBUGS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL;
// LLEventTimer automagically takes care of the lifetime of this object
new QueueTimer(mQueueTimerDelay, this);
}
else {
LL_DEBUGS("LLMediaDataClient") << "not starting queue timer (it's already running, right???)" << LL_ENDL;
}
}
void LLMediaDataClient::stopQueueTimer()
{
mQueueTimerIsRunning = false;
}
bool LLMediaDataClient::processQueueTimer()
{
sortQueue();
if(!isEmpty())
{
LL_INFOS("LLMediaDataClient") << "QueueTimer::tick() started, SORTED queue size is: " << mSortedQueue.size()
<< ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL;
LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, SORTED queue is: " << mSortedQueue << LL_ENDL;
LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, RR queue is: " << mRoundRobinQueue << LL_ENDL;
}
serviceQueue();
LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, SORTED queue size is: " << mSortedQueue.size()
<< ", RR queue size is: " << mRoundRobinQueue.size() << LL_ENDL;
LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, SORTED queue is: " << mSortedQueue << LL_ENDL;
LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, RR queue is: " << mRoundRobinQueue << LL_ENDL;
return isEmpty();
}
void LLMediaDataClient::sortQueue()
{
if(!mSortedQueue.empty())
{
// Score all items first
request_queue_t::iterator iter = mSortedQueue.begin();
request_queue_t::iterator end = mSortedQueue.end();
while (iter != end)
{
(*iter)->updateScore();
iter++;
}
// Re-sort the list...
// NOTE: should this be a stable_sort? If so we need to change to using a vector.
mSortedQueue.sort(LLMediaDataClient::compareRequests);
// ...then cull items over the max
U32 size = mSortedQueue.size();
if (size > mMaxSortedQueueSize)
{
U32 num_to_cull = (size - mMaxSortedQueueSize);
LL_INFOS("LLMediaDataClient") << "sorted queue MAXED OUT! Culling "
<< num_to_cull << " items" << LL_ENDL;
while (num_to_cull-- > 0)
{
mSortedQueue.pop_back();
}
}
}
}
// static
bool LLMediaDataClient::compareRequests(const request_ptr_t &o1, const request_ptr_t &o2)
{
if (o2.isNull()) return true;
if (o1.isNull()) return false;
return ( o1->getScore() > o2->getScore() );
}
void LLMediaDataClient::serviceQueue()
{
request_queue_t *queue_p = getCurrentQueue();
// quick retry loop for cases where we shouldn't wait for the next timer tick
while(true)
{
if (queue_p->empty())
{
LL_DEBUGS("LLMediaDataClient") << "queue empty: " << (*queue_p) << LL_ENDL;
break;
}
// Peel one off of the items from the queue, and execute request
request_ptr_t request = queue_p->front();
llassert(!request.isNull());
const LLMediaDataClientObject *object = (request.isNull()) ? NULL : request->getObject();
llassert(NULL != object);
// Check for conditions that would make us just pop and rapidly loop through
// the queue.
if(request.isNull() ||
request->isMarkedSent() ||
NULL == object ||
object->isDead() ||
!object->hasMedia())
{
if (request.isNull())
{
LL_INFOS("LLMediaDataClient") << "Skipping NULL request" << LL_ENDL;
}
else {
LL_INFOS("LLMediaDataClient") << "Skipping : " << *request << " "
<< ((request->isMarkedSent()) ? " request is marked sent" :
((NULL == object) ? " object is NULL " :
((object->isDead()) ? "object is dead" :
((!object->hasMedia()) ? "object has no media!" : "BADNESS!")))) << LL_ENDL;
}
queue_p->pop_front();
continue; // jump back to the start of the quick retry loop
}
// Next, ask if this is "interesting enough" to fetch. If not, just stop
// and wait for the next timer go-round. Only do this for the sorted
// queue.
if (mCurrentQueueIsTheSortedQueue && !object->isInterestingEnough())
{
LL_DEBUGS("LLMediaDataClient") << "Not fetching " << *request << ": not interesting enough" << LL_ENDL;
break;
}
// Finally, try to send the HTTP message to the cap url
std::string url = request->getCapability();
bool maybe_retry = false;
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, createResponder(request));
}
else {
LL_INFOS("LLMediaDataClient") << "NOT Sending request for " << *request << ": empty cap url!" << LL_ENDL;
maybe_retry = true;
}
bool exceeded_retries = request->getRetryCount() > mMaxNumRetries;
if (maybe_retry && ! exceeded_retries) // Try N times before giving up
{
// We got an empty cap, but in that case we will retry again next
// timer fire.
request->incRetryCount();
}
else {
if (exceeded_retries)
{
LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for "
<< mMaxNumRetries << " tries...popping object id " << object->getID() << LL_ENDL;
// XXX Should we bring up a warning dialog??
}
queue_p->pop_front();
if (! mCurrentQueueIsTheSortedQueue) {
// Round robin
request->markSent(true);
mRoundRobinQueue.push_back(request);
}
}
// end of quick loop -- any cases where we want to loop will use 'continue' to jump back to the start.
break;
}
swapCurrentQueue();
}
void LLMediaDataClient::swapCurrentQueue()
{
// Swap
mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue;
// If its empty, swap back
if (getCurrentQueue()->empty())
{
mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue;
}
}
LLMediaDataClient::request_queue_t *LLMediaDataClient::getCurrentQueue()
{
return (mCurrentQueueIsTheSortedQueue) ? &mSortedQueue : &mRoundRobinQueue;
}
// dump the queue
std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q)
{
int i = 0;
LLMediaDataClient::request_queue_t::const_iterator iter = q.begin();
LLMediaDataClient::request_queue_t::const_iterator end = q.end();
while (iter != end)
{
s << "\t" << i << "]: " << (*iter)->getObject()->getID().asString();
iter++;
i++;
}
return s;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::QueueTimer
// Queue of LLMediaDataClientObject smart pointers to request media for.
//
//////////////////////////////////////////////////////////////////////////////////////
LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc)
: LLEventTimer(time), mMDC(mdc)
{
mMDC->setIsRunning(true);
}
LLMediaDataClient::QueueTimer::~QueueTimer()
{
LL_DEBUGS("LLMediaDataClient") << "~QueueTimer" << LL_ENDL;
mMDC->setIsRunning(false);
mMDC = NULL;
}
// virtual
BOOL LLMediaDataClient::QueueTimer::tick()
{
if (mMDC.isNull()) return TRUE;
return mMDC->processQueueTimer();
}
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::Responder::RetryTimer
//
//////////////////////////////////////////////////////////////////////////////////////
LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr)
: LLEventTimer(time), mResponder(mdr)
{
}
// virtual
LLMediaDataClient::Responder::RetryTimer::~RetryTimer()
{
LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL;
// XXX This is weird: Instead of doing the work in tick() (which re-schedules
// a timer, which might be risky), do it here, in the destructor. Yes, it is very odd.
// 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();
// Release the ref to the responder.
mResponder = NULL;
}
// virtual
BOOL LLMediaDataClient::Responder::RetryTimer::tick()
{
// Don't fire again
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
@ -69,16 +471,18 @@ const U32 LLMediaDataClient::MAX_RETRIES = 4;
//////////////////////////////////////////////////////////////////////////////////////
/*static*/U32 LLMediaDataClient::Request::sNum = 0;
LLMediaDataClient::Request::Request(const std::string &cap_name,
LLMediaDataClient::Request::Request(const char *cap_name,
const LLSD& sd_payload,
LLMediaDataClientObject *obj,
LLMediaDataClient *mdc)
: mCapName(cap_name),
mPayload(sd_payload),
mObject(obj),
mNum(++sNum),
mRetryCount(0),
mMDC(mdc)
: mCapName(cap_name),
mPayload(sd_payload),
mObject(obj),
mNum(++sNum),
mRetryCount(0),
mMDC(mdc),
mMarkedSent(false),
mScore((F64)0.0)
{
}
@ -89,7 +493,7 @@ LLMediaDataClient::Request::~Request()
mObject = NULL;
}
std::string LLMediaDataClient::Request::getCapability() const
{
return getObject()->getCapabilityUrl(getCapName());
@ -99,11 +503,11 @@ std::string LLMediaDataClient::Request::getCapability() const
// discover it.
LLMediaDataClient::Request::Type LLMediaDataClient::Request::getType() const
{
if (mCapName == "ObjectMediaNavigate")
if (0 == strcmp(mCapName, "ObjectMediaNavigate"))
{
return NAVIGATE;
}
else if (mCapName == "ObjectMedia")
else if (0 == strcmp(mCapName, "ObjectMedia"))
{
const std::string &verb = mPayload["verb"];
if (verb == "GET")
@ -133,10 +537,13 @@ const char *LLMediaDataClient::Request::getTypeAsString() const
case NAVIGATE:
return "NAVIGATE";
break;
case ANY:
return "ANY";
break;
}
return "";
}
void LLMediaDataClient::Request::reEnqueue() const
{
@ -147,7 +554,7 @@ void LLMediaDataClient::Request::reEnqueue() const
F32 LLMediaDataClient::Request::getRetryTimerDelay() const
{
return (mMDC == NULL) ? LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY :
mMDC->mRetryTimerDelay;
mMDC->mRetryTimerDelay;
}
U32 LLMediaDataClient::Request::getMaxNumRetries() const
@ -155,52 +562,38 @@ U32 LLMediaDataClient::Request::getMaxNumRetries() const
return (mMDC == NULL) ? LLMediaDataClient::MAX_RETRIES : mMDC->mMaxNumRetries;
}
void LLMediaDataClient::Request::markSent(bool flag)
{
if (mMarkedSent != flag)
{
mMarkedSent = flag;
if (!mMarkedSent)
{
mNum = ++sNum;
}
}
}
void LLMediaDataClient::Request::updateScore()
{
F64 tmp = mObject->getMediaInterest();
if (tmp != mScore)
{
LL_DEBUGS("LLMediaDataClient") << "Score for " << mObject->getID() << " changed from " << mScore << " to " << tmp << LL_ENDL;
mScore = tmp;
}
}
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> ";
s << "request: num=" << r.getNum()
<< " type=" << r.getTypeAsString()
<< " ID=" << r.getObject()->getID()
<< " #retries=" << r.getRetryCount();
return s;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::Responder::RetryTimer
//
//////////////////////////////////////////////////////////////////////////////////////
LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr)
: LLEventTimer(time), mResponder(mdr)
{
}
// virtual
LLMediaDataClient::Responder::RetryTimer::~RetryTimer()
{
LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL;
// XXX This is weird: Instead of doing the work in tick() (which re-schedules
// a timer, which might be risky), do it here, in the destructor. Yes, it is very odd.
// 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();
// Release the ref to the responder.
mResponder = NULL;
}
// virtual
BOOL LLMediaDataClient::Responder::RetryTimer::tick()
{
// Don't fire again
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::Responder
@ -208,7 +601,7 @@ BOOL LLMediaDataClient::Responder::RetryTimer::tick()
//////////////////////////////////////////////////////////////////////////////////////
LLMediaDataClient::Responder::Responder(const request_ptr_t &request)
: mRequest(request)
: mRequest(request)
{
}
@ -224,20 +617,20 @@ void LLMediaDataClient::Responder::error(U32 status, const std::string& reason)
if (status == HTTP_SERVICE_UNAVAILABLE)
{
F32 retry_timeout = mRequest->getRetryTimerDelay();
mRequest->incRetryCount();
if (mRequest->getRetryCount() < mRequest->getMaxNumRetries())
{
LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
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;
LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " <<
mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;
}
}
else {
@ -246,288 +639,10 @@ void LLMediaDataClient::Responder::error(U32 status, const std::string& reason)
}
}
/*virtual*/
void LLMediaDataClient::Responder::result(const LLSD& content)
{
LL_INFOS("LLMediaDataClient") << *mRequest << "result : " << ll_print_sd(content) << LL_ENDL;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::Comparator
//
//////////////////////////////////////////////////////////////////////////////////////
// static
bool LLMediaDataClient::compareRequests(const request_ptr_t &o1, const request_ptr_t &o2)
{
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 = getObjectScore(o1->getObject());
F64 o2_score = getObjectScore(o2->getObject());
return ( o1_score > o2_score );
}
// static
F64 LLMediaDataClient::getObjectScore(const LLMediaDataClientObject::ptr_t &obj)
{
// *TODO: make this less expensive?
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 = obj->getTotalMediaInterest() + 1.0;
return interest/dist;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::PriorityQueue
// Queue of LLMediaDataClientObject smart pointers to request media for.
//
//////////////////////////////////////////////////////////////////////////////////////
// dump the queue
std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q)
{
int i = 0;
LLMediaDataClient::request_queue_t::const_iterator iter = q.begin();
LLMediaDataClient::request_queue_t::const_iterator end = q.end();
while (iter != end)
{
s << "\t" << i << "]: " << (*iter)->getObject()->getID().asString();
iter++;
i++;
}
return s;
}
// find the given object in the queue.
bool LLMediaDataClient::find(const LLMediaDataClientObject::ptr_t &obj) const
{
request_queue_t::const_iterator iter = pRequestQueue->begin();
request_queue_t::const_iterator end = pRequestQueue->end();
while (iter != end)
{
if (obj->getID() == (*iter)->getObject()->getID())
{
return true;
}
iter++;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::QueueTimer
// Queue of LLMediaDataClientObject smart pointers to request media for.
//
//////////////////////////////////////////////////////////////////////////////////////
LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc)
: LLEventTimer(time), mMDC(mdc)
{
mMDC->setIsRunning(true);
}
LLMediaDataClient::QueueTimer::~QueueTimer()
{
LL_DEBUGS("LLMediaDataClient") << "~QueueTimer" << LL_ENDL;
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;
}
request_queue_t &queue = *(mMDC->pRequestQueue);
if(!queue.empty())
{
LL_INFOS("LLMediaDataClient") << "QueueTimer::tick() started, queue is: " << queue << LL_ENDL;
// Re-sort the list every time...
// XXX Is this really what we want?
queue.sort(LLMediaDataClient::compareRequests);
}
// quick retry loop for cases where we shouldn't wait for the next timer tick
while(true)
{
if (queue.empty())
{
LL_DEBUGS("LLMediaDataClient") << "queue empty: " << queue << LL_ENDL;
return TRUE;
}
// Peel one off of the items from the queue, and execute request
request_ptr_t request = queue.front();
llassert(!request.isNull());
const LLMediaDataClientObject *object = (request.isNull()) ? NULL : request->getObject();
bool performed_request = false;
bool error = false;
llassert(NULL != object);
if(object->isDead())
{
// This object has been marked dead. Pop it and move on to the next item in the queue immediately.
LL_INFOS("LLMediaDataClient") << "Skipping " << *request << ": object is dead!" << LL_ENDL;
queue.pop_front();
continue; // jump back to the start of the quick retry loop
}
if (NULL != object && 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 (request.isNull())
{
LL_WARNS("LLMediaDataClient") << "Not Sending request: NULL request!" << LL_ENDL;
}
else if (NULL == object)
{
LL_WARNS("LLMediaDataClient") << "Not Sending request for " << *request << " NULL object!" << LL_ENDL;
}
else if (!object->hasMedia())
{
LL_WARNS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL;
}
error = true;
}
bool exceeded_retries = request->getRetryCount() > mMDC->mMaxNumRetries;
if (performed_request || exceeded_retries || error) // Try N times before giving up
{
if (exceeded_retries)
{
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_front();
}
else {
request->incRetryCount();
}
// end of quick retry loop -- any cases where we want to loop will use 'continue' to jump back to the start.
break;
}
LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue is now: " << (*(mMDC->pRequestQueue)) << LL_ENDL;
return queue.empty();
}
void LLMediaDataClient::startQueueTimer()
{
if (! mQueueTimerIsRunning)
{
LL_INFOS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL;
// LLEventTimer automagically takes care of the lifetime of this object
new QueueTimer(mQueueTimerDelay, this);
}
else {
LL_DEBUGS("LLMediaDataClient") << "not starting queue timer (it's already running, right???)" << LL_ENDL;
}
}
void LLMediaDataClient::stopQueueTimer()
{
mQueueTimerIsRunning = false;
}
void LLMediaDataClient::request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload)
{
if (object.isNull() || ! 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_back(const_cast<LLMediaDataClient::Request*>(request));
LL_DEBUGS("LLMediaDataClient") << "Queue:" << (*pRequestQueue) << LL_ENDL;
// Start the timer if not already running
startQueueTimer();
}
//////////////////////////////////////////////////////////////////////////////////////
//
// 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 request_queue_t();
}
LLMediaDataClient::~LLMediaDataClient()
{
stopQueueTimer();
// This should clear the queue, and hopefully call all the destructors.
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();
}
bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) const
{
return (NULL == pRequestQueue) ? false : find(object);
LL_DEBUGS("LLMediaDataClient") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL;
}
//////////////////////////////////////////////////////////////////////////////////////
@ -569,7 +684,7 @@ void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object)
}
sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data;
LL_INFOS("LLMediaDataClient") << "update media data: " << object->getID() << " " << ll_print_sd(sd_payload) << LL_ENDL;
LL_DEBUGS("LLMediaDataClient") << "update media data: " << object->getID() << " " << ll_print_sd(sd_payload) << LL_ENDL;
request(object, sd_payload);
}
@ -581,7 +696,7 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content)
llassert(type == LLMediaDataClient::Request::GET || type == LLMediaDataClient::Request::UPDATE)
if (type == LLMediaDataClient::Request::GET)
{
LL_INFOS("LLMediaDataClient") << *(getRequest()) << "GET returned: " << ll_print_sd(content) << LL_ENDL;
LL_DEBUGS("LLMediaDataClient") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL;
// Look for an error
if (content.has("error"))
@ -598,12 +713,13 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content)
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;
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]);
getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY],
content[LLTextureEntry::MEDIA_VERSION_KEY]);
}
}
else if (type == LLMediaDataClient::Request::UPDATE)

View File

@ -55,15 +55,19 @@ public:
// 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;
virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &version_string) = 0;
// Return the total "interest" of the media (on-screen area)
virtual F64 getTotalMediaInterest() const = 0;
virtual F64 getMediaInterest() const = 0;
// Return the given cap url
virtual std::string getCapabilityUrl(const std::string &name) const = 0;
// Return whether the object has been marked dead
virtual bool isDead() const = 0;
// Returns a media version number for the object
virtual U32 getMediaVersion() const = 0;
// Returns whether the object is "interesting enough" to fetch
virtual bool isInterestingEnough() const = 0;
// Returns whether we've seen this object yet or not
virtual bool isNew() const = 0;
// smart pointer
typedef LLPointer<LLMediaDataClientObject> ptr_t;
@ -79,11 +83,15 @@ public:
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;
const static U32 MAX_SORTED_QUEUE_SIZE;// = 10000;
const static U32 MAX_ROUND_ROBIN_QUEUE_SIZE;// = 10000;
// Constructor
LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
U32 max_retries = MAX_RETRIES);
U32 max_retries = MAX_RETRIES,
U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE,
U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE);
// Make the request
void request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload);
@ -94,7 +102,13 @@ public:
bool isEmpty() const;
// Returns true iff the given object is in the queue
bool isInQueue(const LLMediaDataClientObject::ptr_t &object) const;
bool isInQueue(const LLMediaDataClientObject::ptr_t &object);
// Remove the given object from the queue. Returns true iff the given object is removed.
bool removeFromQueue(const LLMediaDataClientObject::ptr_t &object);
// Called only by the Queue timer and tests (potentially)
bool processQueueTimer();
protected:
// Destructor
@ -107,11 +121,12 @@ protected:
enum Type {
GET,
UPDATE,
NAVIGATE
NAVIGATE,
ANY
};
Request(const std::string &cap_name, const LLSD& sd_payload, LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
const std::string &getCapName() const { return mCapName; }
Request(const char *cap_name, const LLSD& sd_payload, LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
const char *getCapName() const { return mCapName; }
const LLSD &getPayload() const { return mPayload; }
LLMediaDataClientObject *getObject() const { return mObject; }
@ -132,6 +147,12 @@ protected:
F32 getRetryTimerDelay() const;
U32 getMaxNumRetries() const;
bool isNew() const { return mObject.notNull() ? mObject->isNew() : false; }
void markSent(bool flag);
bool isMarkedSent() const { return mMarkedSent; }
void updateScore();
F64 getScore() const { return mScore; }
public:
friend std::ostream& operator<<(std::ostream &s, const Request &q);
@ -139,14 +160,16 @@ protected:
virtual ~Request(); // use unref();
private:
std::string mCapName;
const char *mCapName;
LLSD mPayload;
LLMediaDataClientObject::ptr_t mObject;
// Simple tracking
const U32 mNum;
U32 mNum;
static U32 sNum;
U32 mRetryCount;
F64 mScore;
bool mMarkedSent;
// Back pointer to the MDC...not a ref!
LLMediaDataClient *mMDC;
};
@ -184,18 +207,23 @@ protected:
};
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:
virtual void sortQueue();
virtual void serviceQueue();
private:
typedef std::list<request_ptr_t> request_queue_t;
void enqueue(const Request*);
// Return whether the given object is/was in the queue
static LLMediaDataClient::request_ptr_t findOrRemove(request_queue_t &queue, const LLMediaDataClientObject::ptr_t &obj, bool remove, Request::Type type);
// Comparator for sorting
static bool compareRequests(const request_ptr_t &o1, const request_ptr_t &o2);
@ -215,34 +243,40 @@ private:
// back-pointer
LLPointer<LLMediaDataClient> mMDC;
};
// Return whether the given object is in the queue
bool find(const LLMediaDataClientObject::ptr_t &obj) const;
void startQueueTimer();
void stopQueueTimer();
void setIsRunning(bool val) { mQueueTimerIsRunning = val; }
void swapCurrentQueue();
request_queue_t *getCurrentQueue();
const F32 mQueueTimerDelay;
const F32 mRetryTimerDelay;
const U32 mMaxNumRetries;
const U32 mMaxSortedQueueSize;
const U32 mMaxRoundRobinQueueSize;
bool mQueueTimerIsRunning;
request_queue_t *pRequestQueue;
request_queue_t mSortedQueue;
request_queue_t mRoundRobinQueue;
bool mCurrentQueueIsTheSortedQueue;
};
// MediaDataResponder specific for the ObjectMedia cap
// MediaDataClient specific for the ObjectMedia cap
class LLObjectMediaDataClient : public LLMediaDataClient
{
public:
LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
U32 max_retries = MAX_RETRIES)
U32 max_retries = MAX_RETRIES,
U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE,
U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE)
: LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
{}
~LLObjectMediaDataClient() {}
virtual ~LLObjectMediaDataClient() {}
void fetchMedia(LLMediaDataClientObject *object);
void updateMedia(LLMediaDataClientObject *object);
@ -264,7 +298,7 @@ protected:
};
// MediaDataResponder specific for the ObjectMediaNavigate cap
// MediaDataClient specific for the ObjectMediaNavigate cap
class LLObjectMediaNavigateClient : public LLMediaDataClient
{
public:
@ -273,10 +307,12 @@ public:
LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
U32 max_retries = MAX_RETRIES)
U32 max_retries = MAX_RETRIES,
U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE,
U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE)
: LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
{}
~LLObjectMediaNavigateClient() {}
virtual ~LLObjectMediaNavigateClient() {}
void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url);

View File

@ -94,7 +94,7 @@ BOOL LLPanelMediaSettingsGeneral::postBuild()
mAutoScale = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_SCALE_KEY );
mAutoZoom = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_ZOOM_KEY );
mControls = getChild< LLComboBox >( LLMediaEntry::CONTROLS_KEY );
mCurrentURL = getChild< LLLineEditor >( LLMediaEntry::CURRENT_URL_KEY );
mCurrentURL = getChild< LLTextBox >( LLMediaEntry::CURRENT_URL_KEY );
mFirstClick = getChild< LLCheckBoxCtrl >( LLMediaEntry::FIRST_CLICK_INTERACT_KEY );
mHeightPixels = getChild< LLSpinCtrl >( LLMediaEntry::HEIGHT_PIXELS_KEY );
mHomeURL = getChild< LLLineEditor >( LLMediaEntry::HOME_URL_KEY );
@ -284,7 +284,7 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& media_
{ LLMediaEntry::AUTO_SCALE_KEY, self->mAutoScale, "LLCheckBoxCtrl" },
{ LLMediaEntry::AUTO_ZOOM_KEY, self->mAutoZoom, "LLCheckBoxCtrl" },
{ LLMediaEntry::CONTROLS_KEY, self->mControls, "LLComboBox" },
{ LLMediaEntry::CURRENT_URL_KEY, self->mCurrentURL, "LLLineEditor" },
{ LLMediaEntry::CURRENT_URL_KEY, self->mCurrentURL, "LLTextBox" },
{ LLMediaEntry::HEIGHT_PIXELS_KEY, self->mHeightPixels, "LLSpinCtrl" },
{ LLMediaEntry::HOME_URL_KEY, self->mHomeURL, "LLLineEditor" },
{ LLMediaEntry::FIRST_CLICK_INTERACT_KEY, self->mFirstClick, "LLCheckBoxCtrl" },
@ -518,4 +518,9 @@ void LLPanelMediaSettingsGeneral::updateCurrentUrl()
bool identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func_current_url, value_str );
mCurrentURL->setText(value_str);
mCurrentURL->setTentative(identical);
if ( LLPanelMediaSettingsGeneral::isMultiple() )
{
mCurrentURL->setText(LLTrans::getString("Multiple Media"));
}
}

View File

@ -99,7 +99,7 @@ private:
LLSpinCtrl* mWidthPixels;
LLSpinCtrl* mHeightPixels;
LLLineEditor* mHomeURL;
LLLineEditor* mCurrentURL;
LLTextBox* mCurrentURL;
LLMediaCtrl* mPreviewMedia;
LLTextBox* mFailWhiteListText;
};

View File

@ -167,6 +167,9 @@ void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media
data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
};
};
// initial update - hides/shows status messages etc.
self->updateWhitelistEnableStatus();
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -630,7 +630,22 @@ bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLView
static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2)
{
return (i1->getProximityDistance() < i2->getProximityDistance());
if(i1->getProximityDistance() < i2->getProximityDistance())
{
return true;
}
else if(i1->getProximityDistance() > i2->getProximityDistance())
{
return false;
}
else
{
// Both objects have the same distance. This most likely means they're two faces of the same object.
// They may also be faces on different objects with exactly the same distance (like HUD objects).
// We don't actually care what the sort order is for this case, as long as it's stable and doesn't change when you enable/disable media.
// Comparing the impl pointers gives a completely arbitrary ordering, but it will be stable.
return (i1 < i2);
}
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

@ -92,7 +92,7 @@ static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
{
public:
LLMediaDataClientObjectImpl(LLVOVolume *obj) : mObject(obj) {}
LLMediaDataClientObjectImpl(LLVOVolume *obj, bool isNew) : mObject(obj), mNew(isNew) {}
LLMediaDataClientObjectImpl() { mObject = NULL; }
virtual U8 getMediaDataCount() const
@ -128,14 +128,19 @@ public:
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 void updateObjectMediaData(LLSD const &data, const std::string &version_string)
{ mObject->updateObjectMediaData(data, version_string); }
virtual F64 getTotalMediaInterest() const
{ return mObject->getTotalMediaInterest(); }
virtual F64 getMediaInterest() const
{
F64 tmp = mObject->getTotalMediaInterest();
return (tmp < 0.0) ? mObject->getPixelArea() : tmp;
}
virtual bool isInterestingEnough() const
{
// TODO: use performance manager to control this
return true;
}
virtual std::string getCapabilityUrl(const std::string &name) const
{ return mObject->getRegion()->getCapability(name); }
@ -143,8 +148,15 @@ public:
virtual bool isDead() const
{ return mObject->isDead(); }
virtual U32 getMediaVersion() const
{ return LLTextureEntry::getVersionFromMediaVersionString(mObject->getMediaURL()); }
virtual bool isNew() const
{ return mNew; }
private:
LLPointer<LLVOVolume> mObject;
bool mNew;
};
@ -165,6 +177,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mSpotLightPriority = 0.f;
mMediaImplList.resize(getNumTEs());
mLastFetchedMediaVersion = -1;
}
LLVOVolume::~LLVOVolume()
@ -190,7 +203,9 @@ void LLVOVolume::markDead()
{
if (!mDead)
{
// TODO: tell LLMediaDataClient to remove this object from its queue
LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false);
sObjectMediaClient->removeFromQueue(obj);
sObjectMediaNavigateClient->removeFromQueue(obj);
// Detach all media impls from this object
for(U32 i = 0 ; i < mMediaImplList.size() ; i++)
@ -210,8 +225,12 @@ void LLVOVolume::initClass()
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);
const U32 max_sorted_queue_size = gSavedSettings.getU32("PrimMediaMaxSortedQueueSize");
const U32 max_round_robin_queue_size = gSavedSettings.getU32("PrimMediaMaxRoundRobinQueueSize");
sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries,
max_sorted_queue_size, max_round_robin_queue_size);
sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay,
max_retries, max_sorted_queue_size, max_round_robin_queue_size);
}
// static
@ -406,7 +425,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
// If the media changed at all, request new media data
LL_DEBUGS("MediaOnAPrim") << "Media update: " << getID() << ": retval=" << retval << " Media URL: " <<
((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL;
requestMediaDataUpdate();
requestMediaDataUpdate(retval & MEDIA_FLAGS_CHANGED);
}
else {
LL_INFOS("MediaOnAPrim") << "Ignoring media update for: " << getID() << " Media URL: " <<
@ -1698,16 +1717,16 @@ LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id)
return result;
}
void LLVOVolume::requestMediaDataUpdate()
void LLVOVolume::requestMediaDataUpdate(bool isNew)
{
sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this));
sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this, isNew));
}
bool LLVOVolume::isMediaDataBeingFetched() const
{
// I know what I'm doing by const_casting this away: this is just
// a wrapper class that is only going to do a lookup.
return sObjectMediaClient->isInQueue(new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this)));
return sObjectMediaClient->isInQueue(new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false));
}
void LLVOVolume::cleanUpMediaImpls()
@ -1725,18 +1744,25 @@ void LLVOVolume::cleanUpMediaImpls()
}
}
void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array)
void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array, const std::string &media_version)
{
// media_data_array is an array of media entry maps
// media_version is the version string in the response.
U32 fetched_version = LLTextureEntry::getVersionFromMediaVersionString(media_version);
//llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl;
LLSD::array_const_iterator iter = media_data_array.beginArray();
LLSD::array_const_iterator end = media_data_array.endArray();
U8 texture_index = 0;
for (; iter != end; ++iter, ++texture_index)
// Only update it if it is newer!
if ( (S32)fetched_version > mLastFetchedMediaVersion)
{
syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/);
mLastFetchedMediaVersion = fetched_version;
//llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl;
LLSD::array_const_iterator iter = media_data_array.beginArray();
LLSD::array_const_iterator end = media_data_array.endArray();
U8 texture_index = 0;
for (; iter != end; ++iter, ++texture_index)
{
syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/);
}
}
}
@ -1904,7 +1930,7 @@ void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plu
llinfos << "broadcasting navigate with URI " << new_location << llendl;
sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this), face_index, new_location);
sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this, false), face_index, new_location);
}
}
@ -1968,7 +1994,7 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
void LLVOVolume::sendMediaDataUpdate()
{
sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this));
sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this, false));
}
void LLVOVolume::removeMediaImpl(S32 texture_index)
@ -2063,7 +2089,7 @@ viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const
F64 LLVOVolume::getTotalMediaInterest() const
{
F64 interest = (F64)0.0;
F64 interest = (F64)-1.0; // means not interested;
int i = 0;
const int end = getNumTEs();
for ( ; i < end; ++i)
@ -2071,6 +2097,7 @@ F64 LLVOVolume::getTotalMediaInterest() const
const viewer_media_t &impl = getMediaImpl(i);
if (!impl.isNull())
{
if (interest == (F64)-1.0) interest = (F64)0.0;
interest += impl->getInterest();
}
}

View File

@ -238,7 +238,7 @@ public:
// 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);
void updateObjectMediaData(const LLSD &media_data_array, const std::string &media_version);
// Bounce back media at the given index to its current URL (or home URL, if current URL is empty)
void mediaNavigateBounceBack(U8 texture_index);
@ -270,13 +270,16 @@ public:
// Returns 'true' iff the media data for this object is in flight
bool isMediaDataBeingFetched() const;
// Returns the "last fetched" media version, or -1 if not fetched yet
S32 getLastFetchedMediaVersion() const { return mLastFetchedMediaVersion; }
protected:
S32 computeLODDetail(F32 distance, F32 radius);
BOOL calcLOD();
LLFace* addFace(S32 face_index);
void updateTEData();
void requestMediaDataUpdate();
void requestMediaDataUpdate(bool isNew);
void cleanUpMediaImpls();
void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;
void removeMediaImpl(S32 texture_index) ;
@ -300,6 +303,7 @@ private:
LLPointer<LLViewerFetchedTexture> mSculptTexture;
LLPointer<LLViewerFetchedTexture> mLightTexture;
media_list_t mMediaImplList;
S32 mLastFetchedMediaVersion; // as fetched from the server, starts as -1
// statics
public:

View File

@ -2669,16 +2669,15 @@ even though the user gets a free copy.
top_pad="5"
name="media_tex"
width="260">
Media URL
Media
</text>
<line_editor
<text
follows="left|top|right"
height="18"
layout="topleft"
left="10"
read_only="true"
name="media_info"
select_on_focus="true"
width="180" />
<button
follows="top|left"

View File

@ -0,0 +1,442 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<mimetypes name="default">
<defaultlabel>
(Unknown)
</defaultlabel>
<defaultwidget>
none
</defaultwidget>
<defaultimpl>
media_plugin_webkit
</defaultimpl>
<widgetset name="web">
<label name="web_label">
Web Content
</label>
<icon>
icn_media_web.tga
</icon>
<default_type>
text/html
</default_type>
<tooltip name="web_tooltip">
This location has Web content
</tooltip>
<playtip name="web_playtip">
Show Web content
</playtip>
<allow_resize>
true
</allow_resize>
<allow_looping>
false
</allow_looping>
</widgetset>
<widgetset name="movie">
<label name="movie_label">
Movie
</label>
<default_type>
video/*
</default_type>
<icon>
icn_media_movie.tga
</icon>
<tooltip name="movie_tooltip">
There is a movie to play here
</tooltip>
<playtip name="movie_playtip">
Play movie
</playtip>
<allow_resize>
false
</allow_resize>
<allow_looping>
true
</allow_looping>
</widgetset>
<widgetset name="image">
<label name="image_label">
Image
</label>
<icon>
icn_media_web.tga
</icon>
<default_type>
image/*
</default_type>
<tooltip name="image_tooltip">
There is an image at this location
</tooltip>
<playtip name="image_playtip">
View this location&apos;s image
</playtip>
<allow_resize>
false
</allow_resize>
<allow_looping>
false
</allow_looping>
</widgetset>
<widgetset name="audio">
<label name="audio_label">
Audio
</label>
<icon>
icn_media_web.tga
</icon>
<default_type>
audio/*
</default_type>
<tooltip name="audio_tooltip">
There is audio at this location
</tooltip>
<playtip name="audio_playtip">
Play this location&apos;s audio
</playtip>
<allow_resize>
false
</allow_resize>
<allow_looping>
true
</allow_looping>
</widgetset>
<scheme name="rtsp">
<label name="rtsp_label">
Real Time Streaming
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</scheme>
<mimetype name="blank">
<label name="blank_label">
- None -
</label>
<widgettype>
none
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype name="none/none">
<label name="none/none_label">
- None -
</label>
<widgettype>
none
</widgettype>
</mimetype>
<mimetype name="audio/*">
<label name="audio2_label">
Audio
</label>
<widgettype>
audio
</widgettype>
</mimetype>
<mimetype name="video/*">
<label name="video2_label">
Video
</label>
<widgettype>
movie
</widgettype>
</mimetype>
<mimetype name="image/*">
<label name="image2_label">
Image
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype menu="1" name="video/vnd.secondlife.qt.legacy">
<label name="vnd.secondlife.qt.legacy_label">
Movie (QuickTime)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype name="application/javascript">
<label name="application/javascript_label">
Javascript
</label>
<widgettype>
web
</widgettype>
</mimetype>
<mimetype name="application/ogg">
<label name="application/ogg_label">
Ogg Audio/Video
</label>
<widgettype>
audio
</widgettype>
</mimetype>
<mimetype name="application/pdf">
<label name="application/pdf_label">
PDF Document
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype name="application/postscript">
<label name="application/postscript_label">
Postscript Document
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype name="application/rtf">
<label name="application/rtf_label">
Rich Text (RTF)
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype name="application/smil">
<label name="application/smil_label">
Synchronized Multimedia Integration Language (SMIL)
</label>
<widgettype>
movie
</widgettype>
</mimetype>
<mimetype name="application/xhtml+xml">
<label name="application/xhtml+xml_label">
Web Page (XHTML)
</label>
<widgettype>
web
</widgettype>
</mimetype>
<mimetype name="application/x-director">
<label name="application/x-director_label">
Macromedia Director
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype name="audio/mid">
<label name="audio/mid_label">
Audio (MIDI)
</label>
<widgettype>
audio
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype name="audio/mpeg">
<label name="audio/mpeg_label">
Audio (MP3)
</label>
<widgettype>
audio
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype name="audio/x-aiff">
<label name="audio/x-aiff_label">
Audio (AIFF)
</label>
<widgettype>
audio
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype name="audio/x-wav">
<label name="audio/x-wav_label">
Audio (WAV)
</label>
<widgettype>
audio
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype menu="1" name="image/bmp">
<label name="image/bmp_label">
Image (BMP)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="image/gif">
<label name="image/gif_label">
Image (GIF)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="image/jpeg">
<label name="image/jpeg_label">
Image (JPEG)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="image/png">
<label name="image/png_label">
Image (PNG)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype name="image/svg+xml">
<label name="image/svg+xml_label">
Image (SVG)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="image/tiff">
<label name="image/tiff_label">
Image (TIFF)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="text/html">
<label name="text/html_label">
Web Page
</label>
<widgettype>
web
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="text/plain">
<label name="text/plain_label">
Text
</label>
<widgettype>
text
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype name="text/xml">
<label name="text/xml_label">
XML
</label>
<widgettype>
text
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="video/mpeg">
<label name="video/mpeg_label">
Movie (MPEG)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype name="video/mp4">
<label name="video/mp4_label">
Movie (MP4)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype menu="1" name="video/quicktime">
<label name="video/quicktime_label">
Movie (QuickTime)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype name="video/x-ms-asf">
<label name="video/x-ms-asf_label">
Movie (Windows Media ASF)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype name="video/x-ms-wmv">
<label name="video/x-ms-wmv_label">
Movie (Windows Media WMV)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
<mimetype menu="1" name="video/x-msvideo">
<label name="video/x-msvideo_label">
Movie (AVI)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_gstreamer
</impl>
</mimetype>
</mimetypes>

View File

@ -0,0 +1,442 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<mimetypes name="default">
<defaultlabel>
(Unknown)
</defaultlabel>
<defaultwidget>
none
</defaultwidget>
<defaultimpl>
media_plugin_webkit
</defaultimpl>
<widgetset name="web">
<label name="web_label">
Web Content
</label>
<icon>
icn_media_web.tga
</icon>
<default_type>
text/html
</default_type>
<tooltip name="web_tooltip">
This location has Web content
</tooltip>
<playtip name="web_playtip">
Show Web content
</playtip>
<allow_resize>
true
</allow_resize>
<allow_looping>
false
</allow_looping>
</widgetset>
<widgetset name="movie">
<label name="movie_label">
Movie
</label>
<default_type>
video/*
</default_type>
<icon>
icn_media_movie.tga
</icon>
<tooltip name="movie_tooltip">
There is a movie to play here
</tooltip>
<playtip name="movie_playtip">
Play movie
</playtip>
<allow_resize>
false
</allow_resize>
<allow_looping>
true
</allow_looping>
</widgetset>
<widgetset name="image">
<label name="image_label">
Image
</label>
<icon>
icn_media_web.tga
</icon>
<default_type>
image/*
</default_type>
<tooltip name="image_tooltip">
There is an image at this location
</tooltip>
<playtip name="image_playtip">
View this location&apos;s image
</playtip>
<allow_resize>
false
</allow_resize>
<allow_looping>
false
</allow_looping>
</widgetset>
<widgetset name="audio">
<label name="audio_label">
Audio
</label>
<icon>
icn_media_web.tga
</icon>
<default_type>
audio/*
</default_type>
<tooltip name="audio_tooltip">
There is audio at this location
</tooltip>
<playtip name="audio_playtip">
Play this location&apos;s audio
</playtip>
<allow_resize>
false
</allow_resize>
<allow_looping>
true
</allow_looping>
</widgetset>
<scheme name="rtsp">
<label name="rtsp_label">
Real Time Streaming
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</scheme>
<mimetype name="blank">
<label name="blank_label">
- None -
</label>
<widgettype>
none
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype name="none/none">
<label name="none/none_label">
- None -
</label>
<widgettype>
none
</widgettype>
</mimetype>
<mimetype name="audio/*">
<label name="audio2_label">
Audio
</label>
<widgettype>
audio
</widgettype>
</mimetype>
<mimetype name="video/*">
<label name="video2_label">
Video
</label>
<widgettype>
movie
</widgettype>
</mimetype>
<mimetype name="image/*">
<label name="image2_label">
Image
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype menu="1" name="video/vnd.secondlife.qt.legacy">
<label name="vnd.secondlife.qt.legacy_label">
Movie (QuickTime)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype name="application/javascript">
<label name="application/javascript_label">
Javascript
</label>
<widgettype>
web
</widgettype>
</mimetype>
<mimetype name="application/ogg">
<label name="application/ogg_label">
Ogg Audio/Video
</label>
<widgettype>
audio
</widgettype>
</mimetype>
<mimetype name="application/pdf">
<label name="application/pdf_label">
PDF Document
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype name="application/postscript">
<label name="application/postscript_label">
Postscript Document
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype name="application/rtf">
<label name="application/rtf_label">
Rich Text (RTF)
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype name="application/smil">
<label name="application/smil_label">
Synchronized Multimedia Integration Language (SMIL)
</label>
<widgettype>
movie
</widgettype>
</mimetype>
<mimetype name="application/xhtml+xml">
<label name="application/xhtml+xml_label">
Web Page (XHTML)
</label>
<widgettype>
web
</widgettype>
</mimetype>
<mimetype name="application/x-director">
<label name="application/x-director_label">
Macromedia Director
</label>
<widgettype>
image
</widgettype>
</mimetype>
<mimetype name="audio/mid">
<label name="audio/mid_label">
Audio (MIDI)
</label>
<widgettype>
audio
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype name="audio/mpeg">
<label name="audio/mpeg_label">
Audio (MP3)
</label>
<widgettype>
audio
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype name="audio/x-aiff">
<label name="audio/x-aiff_label">
Audio (AIFF)
</label>
<widgettype>
audio
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype name="audio/x-wav">
<label name="audio/x-wav_label">
Audio (WAV)
</label>
<widgettype>
audio
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype menu="1" name="image/bmp">
<label name="image/bmp_label">
Image (BMP)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="image/gif">
<label name="image/gif_label">
Image (GIF)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="image/jpeg">
<label name="image/jpeg_label">
Image (JPEG)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="image/png">
<label name="image/png_label">
Image (PNG)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype name="image/svg+xml">
<label name="image/svg+xml_label">
Image (SVG)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="image/tiff">
<label name="image/tiff_label">
Image (TIFF)
</label>
<widgettype>
image
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="text/html">
<label name="text/html_label">
Web Page
</label>
<widgettype>
web
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="text/plain">
<label name="text/plain_label">
Text
</label>
<widgettype>
text
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype name="text/xml">
<label name="text/xml_label">
XML
</label>
<widgettype>
text
</widgettype>
<impl>
media_plugin_webkit
</impl>
</mimetype>
<mimetype menu="1" name="video/mpeg">
<label name="video/mpeg_label">
Movie (MPEG)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype name="video/mp4">
<label name="video/mp4_label">
Movie (MP4)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype menu="1" name="video/quicktime">
<label name="video/quicktime_label">
Movie (QuickTime)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype name="video/x-ms-asf">
<label name="video/x-ms-asf_label">
Movie (Windows Media ASF)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype name="video/x-ms-wmv">
<label name="video/x-ms-wmv_label">
Movie (Windows Media WMV)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
<mimetype menu="1" name="video/x-msvideo">
<label name="video/x-msvideo_label">
Movie (AVI)
</label>
<widgettype>
movie
</widgettype>
<impl>
media_plugin_quicktime
</impl>
</mimetype>
</mimetypes>

View File

@ -579,7 +579,7 @@ Scripts must be allowed to run for weapons to work.
type="alertmodal">
Multiple faces are currently selected.
If you continue this action, separate instances of media will be set on multiple faces of the object.
To place the media on only one face, choose Select Texture and click on the desired face of that object then click Add.
To place the media on only one face, choose Select Face and click on the desired face of that object then click Add.
<usetemplate
ignoretext="Media will be set on multiple selected faces"
name="okcancelignore"

View File

@ -71,7 +71,7 @@
name="current_url_label">
Current URL:
</text>
<line_editor
<text
bottom_delta="-20"
enabled="false"
follows="left|top"

View File

@ -75,15 +75,13 @@
<string>baz</string> \
</array>"
#define _DATA_URLS(ID,DIST,INT,URL1,URL2) " \
#define _DATA_URLS(ID,INTEREST,NEW,URL1,URL2) " \
<llsd> \
<map> \
<key>uuid</key> \
<string>" ID "</string> \
<key>distance</key> \
<real>" DIST "</real> \
<key>interest</key> \
<real>" INT "</real> \
<real>" INTEREST "</real> \
<key>cap_urls</key> \
<map> \
<key>ObjectMedia</key> \
@ -93,21 +91,26 @@
</map> \
<key>media_data</key> \
" MEDIA_DATA " \
<key>is_dead</key> \
<boolean>false</boolean> \
<key>is_new</key> \
<boolean>" NEW "</boolean> \
</map> \
</llsd>"
#define _DATA(ID,DIST,INT) _DATA_URLS(ID,DIST,INT,FAKE_OBJECT_MEDIA_CAP_URL,FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL)
#define _DATA(ID,INTEREST,NEW) _DATA_URLS(ID,INTEREST,NEW,FAKE_OBJECT_MEDIA_CAP_URL,FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL)
const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","1.0");
const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","true");
#define STR(I) boost::lexical_cast<std::string>(I)
#define LOG_TEST(N) LL_DEBUGS("LLMediaDataClient") << "\n" << \
"================================================================================\n" << \
"===================================== TEST " #N " ===================================\n" << \
"==================================== TEST " #N " ===================================\n" << \
"================================================================================\n" << LL_ENDL;
LLSD *gPostRecords = NULL;
F64 gMinimumInterestLevel = (F64)0.0;
// stubs:
void LLHTTPClient::post(
@ -125,21 +128,20 @@ void LLHTTPClient::post(
gPostRecords->append(record);
// Magic URL that triggers a 503:
LLSD result;
result[LLTextureEntry::OBJECT_ID_KEY] = body[LLTextureEntry::OBJECT_ID_KEY];
if ( url == FAKE_OBJECT_MEDIA_CAP_URL_503 )
{
responder->error(HTTP_SERVICE_UNAVAILABLE, "fake reason");
return;
}
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());
}
}
responder->result(result);
}
const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
@ -152,13 +154,12 @@ public:
std::istringstream d(data);
LLSDSerialize::fromXML(mRep, d);
mNumBounceBacks = 0;
mDead = false;
// std::cout << ll_pretty_print_sd(mRep) << std::endl;
// std::cout << "ID: " << getID() << std::endl;
}
LLMediaDataClientObjectTest(const LLSD &rep)
: mRep(rep), mNumBounceBacks(0), mDead(false) {}
: mRep(rep), mNumBounceBacks(0) {}
~LLMediaDataClientObjectTest()
{ LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClientObjectTest" << LL_ENDL; }
@ -169,43 +170,47 @@ public:
virtual LLUUID getID() const
{ return mRep["uuid"]; }
virtual void mediaNavigateBounceBack(U8 index)
{
mNumBounceBacks++;
}
{ 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
virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &media_version)
{ mRep["media_data"] = media_data_array; mRep["media_version"] = media_version; }
virtual F64 getMediaInterest() const
{ return (LLSD::Real)mRep["interest"]; }
virtual bool isInterestingEnough() const
{ return getMediaInterest() > gMinimumInterestLevel; }
virtual std::string getCapabilityUrl(const std::string &name) const
{ return mRep["cap_urls"][name]; }
virtual bool isDead() const
{ return mDead; }
void setDistanceFromAvatar(F64 val)
{ mRep["distance"] = val; }
{ return mRep["is_dead"]; }
void setTotalMediaInterest(F64 val)
virtual U32 getMediaVersion() const
{ return (LLSD::Integer)mRep["media_version"]; }
virtual bool isNew() const
{ return mRep["is_new"]; }
void setMediaInterest(F64 val)
{ mRep["interest"] = val; }
int getNumBounceBacks() const
{ return mNumBounceBacks; }
void markDead()
{ mDead = true; }
{ mRep["is_dead"] = true; }
void markOld()
{ mRep["is_new"] = false; }
private:
LLSD mRep;
int mNumBounceBacks;
bool mDead;
};
// This special timer delay should ensure that the timer will fire on the very
@ -224,10 +229,11 @@ namespace tut
{
mediadataclient() {
gPostRecords = &mLLSD;
gMinimumInterestLevel = (F64)0.0;
//LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
//LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
//LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
// LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
// LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
// LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
}
LLSD mLLSD;
};
@ -378,11 +384,11 @@ namespace tut
LOG_TEST(4);
LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
_DATA(VALID_OBJECT_ID_1,"3.0","1.0"));
_DATA(VALID_OBJECT_ID_1,"1.0","true"));
LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
_DATA(VALID_OBJECT_ID_2,"1.0","1.0"));
_DATA(VALID_OBJECT_ID_2,"3.0","true"));
LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(
_DATA(VALID_OBJECT_ID_3,"2.0","1.0"));
_DATA(VALID_OBJECT_ID_3,"2.0","true"));
{
LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
const char *ORDERED_OBJECT_IDS[] = { VALID_OBJECT_ID_2, VALID_OBJECT_ID_3, VALID_OBJECT_ID_1 };
@ -428,8 +434,7 @@ namespace tut
LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
_DATA_URLS(VALID_OBJECT_ID,
"1.0",
"1.0",
"1.0","true",
FAKE_OBJECT_MEDIA_CAP_URL_503,
FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL));
int num_refs_start = o->getNumRefs();
@ -484,8 +489,7 @@ namespace tut
LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
_DATA_URLS(VALID_OBJECT_ID,
"1.0",
"1.0",
"1.0","true",
FAKE_OBJECT_MEDIA_CAP_URL,
FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR));
{
@ -517,9 +521,9 @@ namespace tut
LOG_TEST(7);
LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
_DATA(VALID_OBJECT_ID_1,"3.0","1.0"));
_DATA(VALID_OBJECT_ID_1,"3.0","true"));
LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
_DATA(VALID_OBJECT_ID_2,"1.0","1.0"));
_DATA(VALID_OBJECT_ID_2,"1.0","true"));
int num_refs_start = o1->getNumRefs();
{
LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
@ -551,10 +555,10 @@ namespace tut
// Test queue handling of objects that are marked dead.
LOG_TEST(8);
LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"1.0","1.0"));
LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"2.0","1.0"));
LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"3.0","1.0"));
LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"4.0","1.0"));
LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"4.0","true"));
LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"3.0","true"));
LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"2.0","true"));
LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"1.0","true"));
{
LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
@ -616,10 +620,11 @@ namespace tut
//
LOG_TEST(9);
LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"10.0","1.0"));
LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"20.0","1.0"));
LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"30.0","1.0"));
LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"40.0","1.0"));
LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"40.0","true"));
LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"30.0","true"));
LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"20.0","true"));
LLMediaDataClientObjectTest *object4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"10.0","true"));
LLMediaDataClientObject::ptr_t o4 = object4;
{
LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
@ -630,53 +635,52 @@ namespace tut
mdc->fetchMedia(o3);
mdc->fetchMedia(o4);
int test_num = 0;
int tick_num = 0;
ensure(STR(test_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(test_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(test_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(test_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(test_num) + ". post records", gPostRecords->size(), 0);
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
::pump_timers();
++test_num;
++tick_num;
// The first tick should remove the first one
ensure(STR(test_num) + ". is not in queue 1", !mdc->isInQueue(o1));
ensure(STR(test_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(test_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(test_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(test_num) + ". post records", gPostRecords->size(), 1);
ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
// Now, pretend that object 4 moved relative to the avatar such
// that it is now closest
static_cast<LLMediaDataClientObjectTest*>(
static_cast<LLMediaDataClientObject*>(o4))->setDistanceFromAvatar(5.0);
object4->setMediaInterest(50.0);
::pump_timers();
++test_num;
++tick_num;
// The second tick should still pick off item 2, but then re-sort
// have picked off object 4
ensure(STR(test_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(test_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(test_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(test_num) + ". post records", gPostRecords->size(), 2);
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
::pump_timers();
++test_num;
++tick_num;
// The third tick should pick off object 2
ensure(STR(test_num) + ". is not in queue 2", !mdc->isInQueue(o2));
ensure(STR(test_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(test_num) + ". post records", gPostRecords->size(), 3);
ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
// The fourth tick should pick off object 3
::pump_timers();
++test_num;
++tick_num;
ensure(STR(test_num) + ". is not in queue 3", !mdc->isInQueue(o3));
ensure(STR(test_num) + ". post records", gPostRecords->size(), 4);
ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
ensure("queue empty", mdc->isEmpty());
}
@ -686,4 +690,249 @@ namespace tut
ensure("refcount of o4", o4->getNumRefs(), 1);
}
template<> template<>
void mediadataclient_object_t::test<10>()
{
//
// Test using the "round-robin" queue
//
LOG_TEST(10);
LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"1.0","true"));
LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"2.0","true"));
LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"3.0","false"));
LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"4.0","false"));
{
LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
// queue up all 4 objects. The first two should be in the sorted
// queue [2 1], the second in the round-robin queue. The queues
// are serviced interleaved, so we should expect:
// 2, 4, 1, 3
mdc->fetchMedia(o1);
mdc->fetchMedia(o2);
mdc->fetchMedia(o3);
mdc->fetchMedia(o4);
int tick_num = 0;
// 0
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
::pump_timers();
++tick_num;
// 1 The first tick should remove object 2
ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
ensure(STR(tick_num) + ". post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_2));
::pump_timers();
++tick_num;
// 2 The second tick should send object 4, but it will still be
// "in the queue"
ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
ensure(STR(tick_num) + ". post object id", (*gPostRecords)[1]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_4));
::pump_timers();
++tick_num;
// 3 The third tick should remove object 1
ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
ensure(STR(tick_num) + ". post object id", (*gPostRecords)[2]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_1));
::pump_timers();
++tick_num;
// 4 The fourth tick should send object 3, but it will still be
// "in the queue"
ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
ensure(STR(tick_num) + ". post object id", (*gPostRecords)[3]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_3));
::pump_timers();
++tick_num;
// 5 The fifth tick should now identify objects 3 and 4 as no longer
// needing "updating", and remove them from the queue
ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
::pump_timers();
// Whew....better be empty
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);
ensure("refcount of o4", o4->getNumRefs(), 1);
}
template<> template<>
void mediadataclient_object_t::test<11>()
{
//
// Test LLMediaDataClient's destructor
//
LOG_TEST(11);
LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
int num_refs_start = o->getNumRefs();
{
LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
mdc->fetchMedia(o);
// must tick enough times to clear refcount of mdc
::pump_timers();
}
// Make sure everyone's destroyed properly
ensure("REF COUNT", o->getNumRefs(), num_refs_start);
}
template<> template<>
void mediadataclient_object_t::test<12>()
{
//
// Test the "not interesting enough" call
//
LOG_TEST(12);
LLMediaDataClientObjectTest *object1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"1.0","true"));
LLMediaDataClientObject::ptr_t o1 = object1;
LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"2.0","true"));
LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"3.0","true"));
LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"4.0","true"));
{
LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
// queue up all 4 objects. The first two are "interesting enough".
// Firing the timer 4 times should therefore leave them.
// Note that they should be sorted 4,3,2,1
// Then, we'll make one "interesting enough", fire the timer a few
// times, and make sure only it gets pulled off the queue
gMinimumInterestLevel = 2.5;
mdc->fetchMedia(o1);
mdc->fetchMedia(o2);
mdc->fetchMedia(o3);
mdc->fetchMedia(o4);
int tick_num = 0;
// 0
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
::pump_timers();
++tick_num;
// 1 The first tick should remove object 4
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
ensure(STR(tick_num) + ". post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_4));
::pump_timers();
++tick_num;
// 2 The second tick should send object 3
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
ensure(STR(tick_num) + ". post object id", (*gPostRecords)[1]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_3));
::pump_timers();
++tick_num;
// 3 The third tick should not pull off anything
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
::pump_timers();
++tick_num;
// 4 The fourth tick (for good measure) should not pull off anything
ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
// Okay, now futz with object 1's interest, such that it is now
// "interesting enough"
object1->setMediaInterest((F64)5.0);
// This should sort so that the queue is now [1 2]
::pump_timers();
++tick_num;
// 5 The fifth tick should now identify objects 3 and 4 as no longer
// needing "updating", and remove them from the queue
ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
ensure(STR(tick_num) + ". post object id", (*gPostRecords)[2]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_1));
::pump_timers();
++tick_num;
// 6 The sixth tick should not pull off anything
ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
::pump_timers();
++tick_num;
// Whew....better NOT be empty ... o2 should still be there
ensure("queue not empty", !mdc->isEmpty());
// But, we need to clear the queue, or else we won't destroy MDC...
// this is a strange interplay between the queue timer and the MDC
ensure("o2 couldn't be removed from queue", mdc->removeFromQueue(o2));
// tick
::pump_timers();
}
ensure("refcount of o1", o1->getNumRefs(), 1);
ensure("refcount of o2", o2->getNumRefs(), 1);
ensure("refcount of o3", o3->getNumRefs(), 1);
ensure("refcount of o4", o4->getNumRefs(), 1);
}
}

View File

@ -803,7 +803,7 @@ class Linux_i686Manifest(LinuxManifest):
# plugins
if self.prefix(src="", dst="bin/llplugin"):
self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so")
self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_quicktime.so")
self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
self.end_prefix("bin/llplugin")
self.path("featuretable_linux.txt")