diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index ecd7c4bc3648c599466b2d87e3b4c468033072be..ddd07dba8064f768f2a9a725ef096d221002677e 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -50,6 +50,7 @@
 						</array>
 					<key>tags</key>
 						<array>
+                          <string>AXON</string>
 						<!-- sample entry for debugging specific items	
 						     <string>Avatar</string>
 						     <string>Inventory</string>
diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index bd99f66459eb2fc81096cda6f708911ab8b104d7..f18d1c636ad30a12ab36dd6be4f764858087c6c6 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -190,3 +190,67 @@ void LLControlAvatar::updateDebugText()
 
     LLVOAvatar::updateDebugText();
 }
+
+void LLControlAvatar::getAnimatedVolumes(std::vector<LLVOVolume*>& volumes)
+{
+    if (!mRootVolp)
+    {
+        return;
+    }
+
+    volumes.push_back(mRootVolp);
+    
+	LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
+	for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
+		 iter != child_list.end(); ++iter)
+	{
+		LLViewerObject* childp = *iter;
+        LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp);
+        if (child_volp && child_volp->isAnimatedObject())
+        {
+            volumes.push_back(child_volp);
+        }
+    }
+}
+
+// This is called after an associated object receives an animation
+// message. Combine the signaled animations for all associated objects
+// and process any resulting state changes.
+void LLControlAvatar::updateAnimations()
+{
+    if (!mRootVolp)
+    {
+        LL_WARNS("AXON") << "No root vol" << LL_ENDL;
+        return;
+    }
+
+    std::vector<LLVOVolume*> volumes;
+    getAnimatedVolumes(volumes);
+    
+    // Rebuild mSignaledAnimations from the associated volumes.
+	std::map<LLUUID, S32> anims;
+    for (std::vector<LLVOVolume*>::iterator vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it)
+    {
+        LLVOVolume *volp = *vol_it;
+        for (std::map<LLUUID,S32>::iterator anim_it = volp->mObjectSignaledAnimations.begin();
+             anim_it != volp->mObjectSignaledAnimations.end();
+             ++anim_it)
+        {
+            std::map<LLUUID,S32>::iterator found_anim_it = anims.find(anim_it->first);
+            if (found_anim_it != anims.end())
+            {
+                // Animation already present, use the larger sequence id
+                anims[anim_it->first] = llmax(found_anim_it->second, anim_it->second);
+            }
+            else
+            {
+                // Animation not already present, use this sequence id.
+                anims[anim_it->first] = anim_it->second;
+            }
+        }
+    }
+    mSignaledAnimations = anims;
+
+    LL_DEBUGS("AXON") << "process animation state changes here" << LL_ENDL;
+    processAnimationStateChanges();
+}
diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h
index fc7b4aa06d9b4e8546ade2dd782915d10f350485..1be2d5844167426d95456920fb1b4f5a39beb1f1 100644
--- a/indra/newview/llcontrolavatar.h
+++ b/indra/newview/llcontrolavatar.h
@@ -51,6 +51,9 @@ class LLControlAvatar:
     void markForDeath();
 
     virtual void idleUpdate(LLAgent &agent, const F64 &time);
+
+    void getAnimatedVolumes(std::vector<LLVOVolume*>& volumes);
+    void updateAnimations();  
     
 	virtual void	updateDebugText();
 
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 227c6afcb0282acce9b4bfbd36aaeead6305ae88..ba4c63258668932054f032c35b014d119d7cb0f4 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5112,22 +5112,19 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data)
         avatarp->mPlaying = true;
 		avatarp->updateVolumeGeom();
     }
-	avatarp->mSignaledAnimations.clear();
+
+	volp->mObjectSignaledAnimations.clear();
 	
     for( S32 i = 0; i < num_blocks; i++ )
     {
         mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
         mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
-        avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
+        volp->mObjectSignaledAnimations[animation_id] = anim_sequence_id;
         LL_DEBUGS("AXON") << "got object animation request for object " 
-                   << uuid << " animation id " << animation_id << LL_ENDL;
+                          << uuid << " animation id " << animation_id << LL_ENDL;
     }
 
-	if (num_blocks >= 0)
-	{
-        LL_DEBUGS("AXON") << "process animation state changes here" << LL_ENDL;
-		avatarp->processAnimationStateChanges();
-	}
+    avatarp->updateAnimations();
 }
 
 
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 9a1629fbfbed1aa554dfa7ae256ab23578c5ce4d..b202f1b848a57e5a6889fc7ebbaf54bfd3db74f5 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -721,6 +721,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 
 	mCurrentGesticulationLevel = 0;
 
+    
 	mRuthTimer.reset();
 	mRuthDebugTimer.reset();
 	mDebugExistenceTimer.reset();
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 27a51d100fd2b169c52d64a43b6ed600cf300f7b..3c0c9facb1c0e661ccf4d5f0ba7b4c16ad2e7868 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -274,6 +274,11 @@ class LLVOVolume : public LLViewerObject
     bool isAnimatedObjectStateConsistent() const;
     void updateAnimatedObjectState(LLViewerObject *old_parent, LLViewerObject *new_parent);
 
+    // AXON For animated objects, we need to track animations requested
+    // per-object, then reconcile those to manage the control avatar
+    // animation state.
+	std::map<LLUUID, S32> 					mObjectSignaledAnimations; // requested state of Animation name/value
+
     // Functions that deal with media, or media navigation
     
     // Update this object's media data with the given media data array
diff --git a/scripts/testing/lsl/cycle_object_animations.lsl b/scripts/testing/lsl/cycle_object_animations.lsl
index 95fa99a1911b7252d298d255ca9f6d012faf4368..79c8ff4151e33409e090bc7eec01a149b2e46230 100644
--- a/scripts/testing/lsl/cycle_object_animations.lsl
+++ b/scripts/testing/lsl/cycle_object_animations.lsl
@@ -9,17 +9,17 @@ cycle_animations()
         ItemName = llGetInventoryName(INVENTORY_ANIMATION, count);
         if (NowPlaying != "")
         {
-            llSay(0, "Stopping " + NowPlaying);
+            //llSay(0, "Stopping " + NowPlaying);
             llStopObjectAnimation(NowPlaying);
         }
-        llSay(0, "Starting " + ItemName);
+        //llSay(0, "Starting " + ItemName);
         llStartObjectAnimation(ItemName);
         NowPlaying = ItemName;
         llSleep(10);
     }
     if (NowPlaying != "")
     {
-        llSay(0, "Stopping " + NowPlaying);
+        //llSay(0, "Stopping " + NowPlaying);
         llStopObjectAnimation(NowPlaying);
         llSleep(10);
     }