STORM-380 FIXED Added syncing animations and sounds before the gesture starts playing.

The actual playing of animations and sounds of a gesture starts only when all needed animations and sound files are loaded into viewer cache. This reduces the delay between animations and sounds meant to be played simultaneously but may increase the delay between the moment a gesture is triggered and the moment it starts playing.

Fixed calling assets callback to clean up the void pointer in getAssetData() and avoid potential memory leaks.
master
Seth ProductEngine 2011-04-22 01:07:52 +03:00
parent 120f31502e
commit e26bfe00ef
3 changed files with 191 additions and 7 deletions

View File

@ -398,6 +398,12 @@ BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType
bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type,
LLGetAssetCallback callback, void *user_data)
{
if (user_data)
{
// The *user_data should not be passed without a callback to clean it up.
llassert(callback != NULL)
}
BOOL exists = mStaticVFS->getExists(uuid, type);
if (exists)
{
@ -432,15 +438,26 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
llinfos << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << llendl;
if (user_data)
{
// The *user_data should not be passed without a callback to clean it up.
llassert(callback != NULL)
}
if (mShutDown)
{
llinfos << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << llendl;
return; // don't get the asset or do any callbacks, we are shutting down
if (callback)
{
callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE);
}
return;
}
if (uuid.isNull())
{
// Special case early out for NULL uuid
// Special case early out for NULL uuid and for shutting down
if (callback)
{
callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);

View File

@ -33,8 +33,10 @@
#include <algorithm>
// library
#include "llaudioengine.h"
#include "lldatapacker.h"
#include "llinventory.h"
#include "llkeyframemotion.h"
#include "llmultigesture.h"
#include "llnotificationsutil.h"
#include "llstl.h"
@ -526,6 +528,66 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture)
gesture->mPlaying = TRUE;
mPlaying.push_back(gesture);
// Load all needed assets to minimize the delays
// when gesture is playing.
for (std::vector<LLGestureStep*>::iterator steps_it = gesture->mSteps.begin();
steps_it != gesture->mSteps.end();
++steps_it)
{
LLGestureStep* step = *steps_it;
switch(step->getType())
{
case STEP_ANIMATION:
{
LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
const LLUUID& anim_id = anim_step->mAnimAssetID;
// Don't request the animation if this step stops it or if it is already in Static VFS
if (!(anim_id.isNull()
|| anim_step->mFlags & ANIM_FLAG_STOP
|| gAssetStorage->hasLocalAsset(anim_id, LLAssetType::AT_ANIMATION)))
{
mLoadingAssets.insert(anim_id);
LLUUID* id = new LLUUID(gAgentID);
gAssetStorage->getAssetData(anim_id,
LLAssetType::AT_ANIMATION,
onAssetLoadComplete,
(void *)id,
TRUE);
}
break;
}
case STEP_SOUND:
{
LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
const LLUUID& sound_id = sound_step->mSoundAssetID;
if (!(sound_id.isNull()
|| gAssetStorage->hasLocalAsset(sound_id, LLAssetType::AT_SOUND)))
{
mLoadingAssets.insert(sound_id);
gAssetStorage->getAssetData(sound_id,
LLAssetType::AT_SOUND,
onAssetLoadComplete,
NULL,
TRUE);
}
break;
}
case STEP_CHAT:
case STEP_WAIT:
case STEP_EOF:
{
break;
}
default:
{
llwarns << "Unknown gesture step type: " << step->getType() << llendl;
}
}
}
// And get it going
stepGesture(gesture);
@ -741,7 +803,7 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture)
{
return;
}
if (!isAgentAvatarValid()) return;
if (!isAgentAvatarValid() || hasLoadingAssets(gesture)) return;
// Of the ones that started playing, have any stopped?
@ -1091,6 +1153,98 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs,
}
}
// static
void LLGestureMgr::onAssetLoadComplete(LLVFS *vfs,
const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data, S32 status, LLExtStat ext_status)
{
LLGestureMgr& self = LLGestureMgr::instance();
// Complete the asset loading process depending on the type and
// remove the asset id from pending downloads list.
switch(type)
{
case LLAssetType::AT_ANIMATION:
{
LLKeyframeMotion::onLoadComplete(vfs, asset_uuid, type, user_data, status, ext_status);
self.mLoadingAssets.erase(asset_uuid);
break;
}
case LLAssetType::AT_SOUND:
{
LLAudioEngine::assetCallback(vfs, asset_uuid, type, user_data, status, ext_status);
self.mLoadingAssets.erase(asset_uuid);
break;
}
default:
{
llwarns << "Unexpected asset type: " << type << llendl;
// We don't want to return from this callback without
// an animation or sound callback being fired
// and *user_data handled to avoid memory leaks.
llassert(type == LLAssetType::AT_ANIMATION || type == LLAssetType::AT_SOUND);
}
}
}
// static
bool LLGestureMgr::hasLoadingAssets(LLMultiGesture* gesture)
{
LLGestureMgr& self = LLGestureMgr::instance();
for (std::vector<LLGestureStep*>::iterator steps_it = gesture->mSteps.begin();
steps_it != gesture->mSteps.end();
++steps_it)
{
LLGestureStep* step = *steps_it;
switch(step->getType())
{
case STEP_ANIMATION:
{
LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
const LLUUID& anim_id = anim_step->mAnimAssetID;
if (!(anim_id.isNull()
|| anim_step->mFlags & ANIM_FLAG_STOP
|| self.mLoadingAssets.find(anim_id) == self.mLoadingAssets.end()))
{
return true;
}
break;
}
case STEP_SOUND:
{
LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
const LLUUID& sound_id = sound_step->mSoundAssetID;
if (!(sound_id.isNull()
|| self.mLoadingAssets.find(sound_id) == self.mLoadingAssets.end()))
{
return true;
}
break;
}
case STEP_CHAT:
case STEP_WAIT:
case STEP_EOF:
{
break;
}
default:
{
llwarns << "Unknown gesture step type: " << step->getType() << llendl;
}
}
}
return false;
}
void LLGestureMgr::stopGesture(LLMultiGesture* gesture)
{

View File

@ -154,9 +154,20 @@ protected:
// Used by loadGesture
static void onLoadComplete(LLVFS *vfs,
const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data, S32 status, LLExtStat ext_status);
const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data, S32 status, LLExtStat ext_status);
// Used by playGesture to load an asset file
// required to play a gesture step
static void onAssetLoadComplete(LLVFS *vfs,
const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data, S32 status, LLExtStat ext_status);
// Checks whether all animation and sound assets
// needed to play a gesture are loaded.
static bool hasLoadingAssets(LLMultiGesture* gesture);
private:
// Active gestures.
@ -172,6 +183,8 @@ private:
callback_map_t mCallbackMap;
std::vector<LLMultiGesture*> mPlaying;
BOOL mValid;
std::set<LLUUID> mLoadingAssets;
};
#endif