/indra/newview/llspeakingindicatormanager.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 318 lines · 157 code · 48 blank · 113 comment · 26 complexity · 5467ab98df434227d75af33d71982b8a MD5 · raw file

  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=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #include "llviewerprecompiledheaders.h"
  29. #include "llspeakingindicatormanager.h"
  30. #include "llvoicechannel.h"
  31. #include "llvoiceclient.h"
  32. /**
  33. * This class intended to control visibility of avatar speaking indicators depend on whether avatars
  34. * are in the same voice channel.
  35. *
  36. * Speaking indicator should be visible for avatars in the same voice channel. See EXT-3976.
  37. *
  38. * It stores passed instances of LLOutputMonitorCtrl in a multimap by avatar LLUUID.
  39. * It observes changing of voice channel and changing of participant list in voice channel.
  40. * When voice channel or voice participant list is changed it updates visibility of an appropriate
  41. * speaking indicator.
  42. *
  43. * Several indicators can be registered for the same avatar.
  44. */
  45. class SpeakingIndicatorManager : public LLSingleton<SpeakingIndicatorManager>, LLVoiceClientParticipantObserver
  46. {
  47. LOG_CLASS(SpeakingIndicatorManager);
  48. public:
  49. /**
  50. * Stores passed speaking indicator to control its visibility.
  51. *
  52. * Registered indicator is set visible if an appropriate avatar is in the same voice channel with Agent.
  53. * It ignores instances of Agent's indicator.
  54. *
  55. * @param speaker_id LLUUID of an avatar whose speaking indicator is registered.
  56. * @param speaking_indicator instance of the speaking indicator to be registered.
  57. * @param session_id session UUID for which indicator should be shown only.
  58. * If this parameter is set registered indicator will be shown only in voice channel
  59. * which has the same session id (EXT-5562).
  60. */
  61. void registerSpeakingIndicator(const LLUUID& speaker_id, LLSpeakingIndicator* const speaking_indicator,
  62. const LLUUID& session_id = LLUUID::null);
  63. /**
  64. * Removes passed speaking indicator from observing.
  65. *
  66. * @param speaker_id LLUUID of an avatar whose speaking indicator should be unregistered.
  67. * @param speaking_indicator instance of the speaking indicator to be unregistered.
  68. */
  69. void unregisterSpeakingIndicator(const LLUUID& speaker_id, const LLSpeakingIndicator* const speaking_indicator);
  70. private:
  71. typedef std::set<LLUUID> speaker_ids_t;
  72. typedef std::multimap<LLUUID, LLSpeakingIndicator*> speaking_indicators_mmap_t;
  73. typedef speaking_indicators_mmap_t::value_type speaking_indicator_value_t;
  74. typedef speaking_indicators_mmap_t::const_iterator indicator_const_iterator;
  75. typedef std::pair<indicator_const_iterator, indicator_const_iterator> indicator_range_t;
  76. friend class LLSingleton<SpeakingIndicatorManager>;
  77. SpeakingIndicatorManager();
  78. ~SpeakingIndicatorManager();
  79. /**
  80. * Callback to determine when voice channel is changed.
  81. *
  82. * It switches all registered speaking indicators off.
  83. * To reduce overheads only switched on indicators are processed.
  84. */
  85. void sOnCurrentChannelChanged(const LLUUID& session_id);
  86. /**
  87. * Callback of changing voice participant list (from LLVoiceClientParticipantObserver).
  88. *
  89. * Switches off indicators had been switched on and switches on indicators of current participants list.
  90. * There is only a few indicators in lists should be switched off/on.
  91. * So, method does not calculate difference between these list it only switches off already
  92. * switched on indicators and switches on indicators of voice channel participants
  93. */
  94. void onParticipantsChanged();
  95. /**
  96. * Changes state of indicators specified by LLUUIDs
  97. *
  98. * @param speakers_uuids - avatars' LLUUIDs whose speaking indicators should be switched
  99. * @param switch_on - if TRUE specified indicator will be switched on, off otherwise.
  100. */
  101. void switchSpeakerIndicators(const speaker_ids_t& speakers_uuids, BOOL switch_on);
  102. /**
  103. * Ensures that passed instance of Speaking Indicator does not exist among registered ones.
  104. * If yes, it will be removed.
  105. */
  106. void ensureInstanceDoesNotExist(LLSpeakingIndicator* const speaking_indicator);
  107. /**
  108. * Multimap with all registered speaking indicators
  109. */
  110. speaking_indicators_mmap_t mSpeakingIndicators;
  111. /**
  112. * LUUIDs of avatar for which we have speaking indicators switched on.
  113. *
  114. * Is used to switch off all previously ON indicators when voice participant list is changed.
  115. *
  116. * @see onChange()
  117. */
  118. speaker_ids_t mSwitchedIndicatorsOn;
  119. };
  120. //////////////////////////////////////////////////////////////////////////
  121. // PUBLIC SECTION
  122. //////////////////////////////////////////////////////////////////////////
  123. void SpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker_id, LLSpeakingIndicator* const speaking_indicator,
  124. const LLUUID& session_id)
  125. {
  126. // do not exclude agent's indicators. They should be processed in the same way as others. See EXT-3889.
  127. LL_DEBUGS("SpeakingIndicator") << "Registering indicator: " << speaker_id << "|"<< speaking_indicator << ", session: " << session_id << LL_ENDL;
  128. ensureInstanceDoesNotExist(speaking_indicator);
  129. speaking_indicator->setTargetSessionID(session_id);
  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()->isParticipant(speaker_id);
  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::onParticipantsChanged()
  175. {
  176. LL_DEBUGS("SpeakingIndicator") << "Voice participant list was changed, updating indicators" << LL_ENDL;
  177. speaker_ids_t speakers_uuids;
  178. LLVoiceClient::getInstance()->getParticipantList(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. LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();
  190. LLUUID session_id;
  191. if (voice_channel)
  192. {
  193. session_id = voice_channel->getSessionID();
  194. }
  195. speaker_ids_t::const_iterator it_uuid = speakers_uuids.begin();
  196. for (; it_uuid != speakers_uuids.end(); ++it_uuid)
  197. {
  198. LL_DEBUGS("SpeakingIndicator") << "Looking for indicator: " << *it_uuid << LL_ENDL;
  199. indicator_range_t it_range = mSpeakingIndicators.equal_range(*it_uuid);
  200. indicator_const_iterator it_indicator = it_range.first;
  201. bool was_found = false;
  202. bool was_switched_on = false;
  203. for (; it_indicator != it_range.second; ++it_indicator)
  204. {
  205. was_found = true;
  206. LLSpeakingIndicator* indicator = (*it_indicator).second;
  207. BOOL switch_current_on = switch_on;
  208. // we should show indicator for specified voice session only if this is current channel. EXT-5562.
  209. if (switch_current_on && indicator->getTargetSessionID().notNull())
  210. {
  211. switch_current_on = indicator->getTargetSessionID() == session_id;
  212. LL_DEBUGS("SpeakingIndicator") << "Session: " << session_id << ", target: " << indicator->getTargetSessionID() << ", the same? = " << switch_current_on << LL_ENDL;
  213. }
  214. was_switched_on = was_switched_on || switch_current_on;
  215. indicator->switchIndicator(switch_current_on);
  216. }
  217. if (was_found)
  218. {
  219. LL_DEBUGS("SpeakingIndicator") << mSpeakingIndicators.count(*it_uuid) << " indicators where found" << LL_ENDL;
  220. if (switch_on && !was_switched_on)
  221. {
  222. LL_DEBUGS("SpeakingIndicator") << "but non of them where switched on" << LL_ENDL;
  223. }
  224. if (was_switched_on)
  225. {
  226. // store switched on indicator to be able switch it off
  227. mSwitchedIndicatorsOn.insert(*it_uuid);
  228. }
  229. }
  230. }
  231. }
  232. void SpeakingIndicatorManager::ensureInstanceDoesNotExist(LLSpeakingIndicator* const speaking_indicator)
  233. {
  234. LL_DEBUGS("SpeakingIndicator") << "Searching for an registered indicator instance: " << speaking_indicator << LL_ENDL;
  235. speaking_indicators_mmap_t::iterator it = mSpeakingIndicators.begin();
  236. for (;it != mSpeakingIndicators.end(); ++it)
  237. {
  238. if (it->second == speaking_indicator)
  239. {
  240. LL_DEBUGS("SpeakingIndicator") << "Found" << LL_ENDL;
  241. break;
  242. }
  243. }
  244. // It is possible with LLOutputMonitorCtrl the same instance of indicator is registered several
  245. // times with different UUIDs. This leads to crash after instance is destroyed because the
  246. // only one (specified by UUID in unregisterSpeakingIndicator()) is removed from the map.
  247. // So, using stored deleted pointer leads to crash. See EXT-4782.
  248. if (it != mSpeakingIndicators.end())
  249. {
  250. llwarns << "The same instance of indicator has already been registered, removing it: " << it->first << "|"<< speaking_indicator << llendl;
  251. llassert(it == mSpeakingIndicators.end());
  252. mSpeakingIndicators.erase(it);
  253. }
  254. }
  255. /************************************************************************/
  256. /* LLSpeakingIndicatorManager namespace implementation */
  257. /************************************************************************/
  258. void LLSpeakingIndicatorManager::registerSpeakingIndicator(const LLUUID& speaker_id, LLSpeakingIndicator* const speaking_indicator,
  259. const LLUUID& session_id)
  260. {
  261. SpeakingIndicatorManager::instance().registerSpeakingIndicator(speaker_id, speaking_indicator, session_id);
  262. }
  263. void LLSpeakingIndicatorManager::unregisterSpeakingIndicator(const LLUUID& speaker_id, const LLSpeakingIndicator* const speaking_indicator)
  264. {
  265. if(SpeakingIndicatorManager::instanceExists())
  266. {
  267. SpeakingIndicatorManager::instance().unregisterSpeakingIndicator(speaker_id, speaking_indicator);
  268. }
  269. }
  270. // EOF