llspeakingindicatormanager.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:11k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llspeakingindicatormanager.cpp
  3.  * @author Mike Antipov
  4.  * @brief Implementation of SpeackerIndicatorManager class to process registered LLSpeackerIndicator
  5.  * depend on avatars are in the same voice channel.
  6.  *
  7.  * $LicenseInfo:firstyear=2010&license=viewergpl$
  8.  * 
  9.  * Copyright (c) 2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  */
  34. #include "llviewerprecompiledheaders.h"
  35. #include "llspeakingindicatormanager.h"
  36. #include "llvoicechannel.h"
  37. #include "llvoiceclient.h"
  38. /**
  39.  * This class intended to control visibility of avatar speaking indicators depend on whether avatars
  40.  * are in the same voice channel.
  41.  *
  42.  * Speaking indicator should be visible for avatars in the same voice channel. See EXT-3976.
  43.  *
  44.  * It stores passed instances of LLOutputMonitorCtrl in a multimap by avatar LLUUID.
  45.  * It observes changing of voice channel and changing of participant list in voice channel.
  46.  * When voice channel or voice participant list is changed it updates visibility of an appropriate 
  47.  * speaking indicator.
  48.  *
  49.  * Several indicators can be registered for the same avatar.
  50.  */
  51. class SpeakingIndicatorManager : public LLSingleton<SpeakingIndicatorManager>, LLVoiceClientParticipantObserver
  52. {
  53. LOG_CLASS(SpeakingIndicatorManager);
  54. public:
  55. /**
  56.  * Stores passed speaking indicator to control its visibility.
  57.  *
  58.  * Registered indicator is set visible if an appropriate avatar is in the same voice channel with Agent.
  59.  * It ignores instances of Agent's indicator.
  60.  *
  61.  * @param speaker_id LLUUID of an avatar whose speaking indicator is registered.
  62.  * @param speaking_indicator instance of the speaking indicator to be registered.
  63.  */
  64. void registerSpeakingIndicator(const LLUUID& speaker_id, LLSpeakingIndicator* const speaking_indicator);
  65. /**
  66.  * Removes passed speaking indicator from observing.
  67.  *
  68.  * @param speaker_id LLUUID of an avatar whose speaking indicator should be unregistered.
  69.  * @param speaking_indicator instance of the speaking indicator to be unregistered.
  70.  */
  71. void unregisterSpeakingIndicator(const LLUUID& speaker_id, const LLSpeakingIndicator* const speaking_indicator);
  72. private:
  73. typedef std::set<LLUUID> speaker_ids_t;
  74. typedef std::multimap<LLUUID, LLSpeakingIndicator*> speaking_indicators_mmap_t;
  75. typedef speaking_indicators_mmap_t::value_type speaking_indicator_value_t;
  76. typedef speaking_indicators_mmap_t::const_iterator indicator_const_iterator;
  77. typedef std::pair<indicator_const_iterator, indicator_const_iterator> indicator_range_t;
  78. friend class LLSingleton<SpeakingIndicatorManager>;
  79. SpeakingIndicatorManager();
  80. ~SpeakingIndicatorManager();
  81. /**
  82.  * Callback to determine when voice channel is changed.
  83.  *
  84.  * It switches all registered speaking indicators off.
  85.  * To reduce overheads only switched on indicators are processed.
  86.  */
  87. void sOnCurrentChannelChanged(const LLUUID& session_id);
  88. /**
  89.  * Callback of changing voice participant list (from LLVoiceClientParticipantObserver).
  90.  *
  91.  * Switches off indicators had been switched on and switches on indicators of current participants list.
  92.  * There is only a few indicators in lists should be switched off/on.
  93.  * So, method does not calculate difference between these list it only switches off already 
  94.  * switched on indicators and switches on indicators of voice channel participants
  95.  */
  96. void onChange();
  97. /**
  98.  * Changes state of indicators specified by LLUUIDs
  99.  *
  100.  * @param speakers_uuids - avatars' LLUUIDs whose speaking indicators should be switched
  101.  * @param switch_on - if TRUE specified indicator will be switched on, off otherwise.
  102.  */
  103. void switchSpeakerIndicators(const speaker_ids_t& speakers_uuids, BOOL switch_on);
  104. /**
  105.  * Ensures that passed instance of Speaking Indicator does not exist among registered ones.
  106.  * If yes, it will be removed.
  107.  */
  108. void ensureInstanceDoesNotExist(LLSpeakingIndicator* const speaking_indicator);
  109. /**
  110.  * Multimap with all registered speaking indicators
  111.  */
  112. speaking_indicators_mmap_t mSpeakingIndicators;
  113. /**
  114.  * LUUIDs of avatar for which we have speaking indicators switched on.
  115.  *
  116.  * Is used to switch off all previously ON indicators when voice participant list is changed.
  117.  *
  118.  * @see onChange()
  119.  */
  120. speaker_ids_t mSwitchedIndicatorsOn;
  121. };
  122. //////////////////////////////////////////////////////////////////////////
  123. // PUBLIC SECTION
  124. //////////////////////////////////////////////////////////////////////////
  125. void SpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker_id, LLSpeakingIndicator* const speaking_indicator)
  126. {
  127. // do not exclude agent's indicators. They should be processed in the same way as others. See EXT-3889.
  128. LL_DEBUGS("SpeakingIndicator") << "Registering indicator: " << speaker_id << "|"<< speaking_indicator << LL_ENDL;
  129. ensureInstanceDoesNotExist(speaking_indicator);
  130. speaking_indicator_value_t value_type(speaker_id, speaking_indicator);
  131. mSpeakingIndicators.insert(value_type);
  132. speaker_ids_t speakers_uuids;
  133. BOOL is_in_same_voice = LLVoiceClient::getInstance()->findParticipantByID(speaker_id) != NULL;
  134. speakers_uuids.insert(speaker_id);
  135. switchSpeakerIndicators(speakers_uuids, is_in_same_voice);
  136. }
  137. void SpeakingIndicatorManager::unregisterSpeakingIndicator(const LLUUID& speaker_id, const LLSpeakingIndicator* const speaking_indicator)
  138. {
  139. LL_DEBUGS("SpeakingIndicator") << "Unregistering indicator: " << speaker_id << "|"<< speaking_indicator << LL_ENDL;
  140. speaking_indicators_mmap_t::iterator it;
  141. it = mSpeakingIndicators.find(speaker_id);
  142. for (;it != mSpeakingIndicators.end(); ++it)
  143. {
  144. if (it->second == speaking_indicator)
  145. {
  146. LL_DEBUGS("SpeakingIndicator") << "Unregistered." << LL_ENDL;
  147. mSpeakingIndicators.erase(it);
  148. break;
  149. }
  150. }
  151. }
  152. //////////////////////////////////////////////////////////////////////////
  153. // PRIVATE SECTION
  154. //////////////////////////////////////////////////////////////////////////
  155. SpeakingIndicatorManager::SpeakingIndicatorManager()
  156. {
  157. LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&SpeakingIndicatorManager::sOnCurrentChannelChanged, this, _1));
  158. LLVoiceClient::getInstance()->addObserver(this);
  159. }
  160. SpeakingIndicatorManager::~SpeakingIndicatorManager()
  161. {
  162. // Don't use LLVoiceClient::getInstance() here without check
  163. // singleton MAY have already been destroyed.
  164. if(LLVoiceClient::instanceExists())
  165. {
  166. LLVoiceClient::getInstance()->removeObserver(this);
  167. }
  168. }
  169. void SpeakingIndicatorManager::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)
  170. {
  171. switchSpeakerIndicators(mSwitchedIndicatorsOn, FALSE);
  172. mSwitchedIndicatorsOn.clear();
  173. }
  174. void SpeakingIndicatorManager::onChange()
  175. {
  176. LL_DEBUGS("SpeakingIndicator") << "Voice participant list was changed, updating indicators" << LL_ENDL;
  177. speaker_ids_t speakers_uuids;
  178. LLVoiceClient::getInstance()->getParticipantsUUIDSet(speakers_uuids);
  179. LL_DEBUGS("SpeakingIndicator") << "Switching all OFF, count: " << mSwitchedIndicatorsOn.size() << LL_ENDL;
  180. // switch all indicators off
  181. switchSpeakerIndicators(mSwitchedIndicatorsOn, FALSE);
  182. mSwitchedIndicatorsOn.clear();
  183. LL_DEBUGS("SpeakingIndicator") << "Switching all ON, count: " << speakers_uuids.size() << LL_ENDL;
  184. // then switch current voice participants indicators on
  185. switchSpeakerIndicators(speakers_uuids, TRUE);
  186. }
  187. void SpeakingIndicatorManager::switchSpeakerIndicators(const speaker_ids_t& speakers_uuids, BOOL switch_on)
  188. {
  189. speaker_ids_t::const_iterator it_uuid = speakers_uuids.begin(); 
  190. for (; it_uuid != speakers_uuids.end(); ++it_uuid)
  191. {
  192. LL_DEBUGS("SpeakingIndicator") << "Looking for indicator: " << *it_uuid << LL_ENDL;
  193. indicator_range_t it_range = mSpeakingIndicators.equal_range(*it_uuid);
  194. indicator_const_iterator it_indicator = it_range.first;
  195. bool was_found = false;
  196. for (; it_indicator != it_range.second; ++it_indicator)
  197. {
  198. was_found = true;
  199. LLSpeakingIndicator* indicator = (*it_indicator).second;
  200. indicator->switchIndicator(switch_on);
  201. }
  202. if (was_found)
  203. {
  204. LL_DEBUGS("SpeakingIndicator") << mSpeakingIndicators.count(*it_uuid) << " indicators where found" << LL_ENDL;
  205. if (switch_on)
  206. {
  207. // store switched on indicator to be able switch it off
  208. mSwitchedIndicatorsOn.insert(*it_uuid);
  209. }
  210. }
  211. }
  212. }
  213. void SpeakingIndicatorManager::ensureInstanceDoesNotExist(LLSpeakingIndicator* const speaking_indicator)
  214. {
  215. LL_DEBUGS("SpeakingIndicator") << "Searching for an registered indicator instance: " << speaking_indicator << LL_ENDL;
  216. speaking_indicators_mmap_t::iterator it = mSpeakingIndicators.begin();
  217. for (;it != mSpeakingIndicators.end(); ++it)
  218. {
  219. if (it->second == speaking_indicator)
  220. {
  221. LL_DEBUGS("SpeakingIndicator") << "Found" << LL_ENDL;
  222. break;
  223. }
  224. }
  225. // It is possible with LLOutputMonitorCtrl the same instance of indicator is registered several
  226. // times with different UUIDs. This leads to crash after instance is destroyed because the
  227. // only one (specified by UUID in unregisterSpeakingIndicator()) is removed from the map.
  228. // So, using stored deleted pointer leads to crash. See EXT-4782.
  229. if (it != mSpeakingIndicators.end())
  230. {
  231. llwarns << "The same instance of indicator has already been registered, removing it: " << it->first << "|"<< speaking_indicator << llendl;
  232. llassert(it == mSpeakingIndicators.end());
  233. mSpeakingIndicators.erase(it);
  234. }
  235. }
  236. /************************************************************************/
  237. /*         LLSpeakingIndicatorManager namespace implementation          */
  238. /************************************************************************/
  239. void LLSpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker_id, LLSpeakingIndicator* const speaking_indicator)
  240. {
  241. SpeakingIndicatorManager::instance().registerSpeakingIndicator(speaker_id, speaking_indicator);
  242. }
  243. void LLSpeakingIndicatorManager::unregisterSpeakingIndicator(const LLUUID& speaker_id, const LLSpeakingIndicator* const speaking_indicator)
  244. {
  245. SpeakingIndicatorManager::instance().unregisterSpeakingIndicator(speaker_id, speaking_indicator);
  246. }
  247. // EOF