PageRenderTime 48ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llspeakers.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 929 lines | 699 code | 131 blank | 99 comment | 158 complexity | d62d9255718394d9ec3fc41090cf17b7 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llspeakers.cpp
  3. * @brief Management interface for muting and controlling volume of residents currently speaking
  4. *
  5. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llspeakers.h"
  28. #include "llagent.h"
  29. #include "llappviewer.h"
  30. #include "llimview.h"
  31. #include "llsdutil.h"
  32. #include "lluicolortable.h"
  33. #include "llviewerobjectlist.h"
  34. #include "llvoavatar.h"
  35. #include "llworld.h"
  36. const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f);
  37. const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f);
  38. LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) :
  39. mStatus(LLSpeaker::STATUS_TEXT_ONLY),
  40. mLastSpokeTime(0.f),
  41. mSpeechVolume(0.f),
  42. mHasSpoken(FALSE),
  43. mHasLeftCurrentCall(FALSE),
  44. mDotColor(LLColor4::white),
  45. mID(id),
  46. mTyping(FALSE),
  47. mSortIndex(0),
  48. mType(type),
  49. mIsModerator(FALSE),
  50. mModeratorMutedVoice(FALSE),
  51. mModeratorMutedText(FALSE)
  52. {
  53. if (name.empty() && type == SPEAKER_AGENT)
  54. {
  55. lookupName();
  56. }
  57. else
  58. {
  59. mDisplayName = name;
  60. }
  61. }
  62. void LLSpeaker::lookupName()
  63. {
  64. if (mDisplayName.empty())
  65. {
  66. gCacheName->get(mID, false, boost::bind(&LLSpeaker::onNameCache, this, _1, _2, _3));
  67. }
  68. }
  69. void LLSpeaker::onNameCache(const LLUUID& id, const std::string& full_name, bool is_group)
  70. {
  71. mDisplayName = full_name;
  72. }
  73. bool LLSpeaker::isInVoiceChannel()
  74. {
  75. return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED;
  76. }
  77. LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source)
  78. : LLEvent(source, "Speaker add moderator event"),
  79. mSpeakerID (source->mID),
  80. mIsModerator (source->mIsModerator)
  81. {
  82. }
  83. LLSD LLSpeakerUpdateModeratorEvent::getValue()
  84. {
  85. LLSD ret;
  86. ret["id"] = mSpeakerID;
  87. ret["is_moderator"] = mIsModerator;
  88. return ret;
  89. }
  90. LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source)
  91. : LLEvent(source, "Speaker text moderation event")
  92. {
  93. }
  94. LLSD LLSpeakerTextModerationEvent::getValue()
  95. {
  96. return std::string("text");
  97. }
  98. LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source)
  99. : LLEvent(source, "Speaker voice moderation event")
  100. {
  101. }
  102. LLSD LLSpeakerVoiceModerationEvent::getValue()
  103. {
  104. return std::string("voice");
  105. }
  106. LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id)
  107. : LLEvent(source, "Speaker added/removed from speaker mgr"),
  108. mSpeakerID(speaker_id)
  109. {
  110. }
  111. LLSD LLSpeakerListChangeEvent::getValue()
  112. {
  113. return mSpeakerID;
  114. }
  115. // helper sort class
  116. struct LLSortRecentSpeakers
  117. {
  118. bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const;
  119. };
  120. bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const
  121. {
  122. // Sort first on status
  123. if (lhs->mStatus != rhs->mStatus)
  124. {
  125. return (lhs->mStatus < rhs->mStatus);
  126. }
  127. // and then on last speaking time
  128. if(lhs->mLastSpokeTime != rhs->mLastSpokeTime)
  129. {
  130. return (lhs->mLastSpokeTime > rhs->mLastSpokeTime);
  131. }
  132. // and finally (only if those are both equal), on name.
  133. return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 );
  134. }
  135. LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id)
  136. : LLEventTimer(action_period)
  137. , mActionCallback(action_cb)
  138. , mSpeakerId(speaker_id)
  139. {
  140. }
  141. BOOL LLSpeakerActionTimer::tick()
  142. {
  143. if (mActionCallback)
  144. {
  145. return (BOOL)mActionCallback(mSpeakerId);
  146. }
  147. return TRUE;
  148. }
  149. void LLSpeakerActionTimer::unset()
  150. {
  151. mActionCallback = 0;
  152. }
  153. LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay)
  154. : mActionCallback(action_cb)
  155. , mActionDelay(action_delay)
  156. {
  157. }
  158. LLSpeakersDelayActionsStorage::~LLSpeakersDelayActionsStorage()
  159. {
  160. removeAllTimers();
  161. }
  162. void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id)
  163. {
  164. bool not_found = true;
  165. if (mActionTimersMap.size() > 0)
  166. {
  167. not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end();
  168. }
  169. // If there is already a started timer for the passed UUID don't do anything.
  170. if (not_found)
  171. {
  172. // Starting a timer to remove an participant after delay is completed
  173. mActionTimersMap.insert(LLSpeakerActionTimer::action_value_t(speaker_id,
  174. new LLSpeakerActionTimer(
  175. boost::bind(&LLSpeakersDelayActionsStorage::onTimerActionCallback, this, _1),
  176. mActionDelay, speaker_id)));
  177. }
  178. }
  179. void LLSpeakersDelayActionsStorage::unsetActionTimer(const LLUUID& speaker_id)
  180. {
  181. if (mActionTimersMap.size() == 0) return;
  182. LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id);
  183. if (it_speaker != mActionTimersMap.end())
  184. {
  185. it_speaker->second->unset();
  186. mActionTimersMap.erase(it_speaker);
  187. }
  188. }
  189. void LLSpeakersDelayActionsStorage::removeAllTimers()
  190. {
  191. LLSpeakerActionTimer::action_timer_iter_t iter = mActionTimersMap.begin();
  192. for (; iter != mActionTimersMap.end(); ++iter)
  193. {
  194. delete iter->second;
  195. }
  196. mActionTimersMap.clear();
  197. }
  198. bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_id)
  199. {
  200. unsetActionTimer(speaker_id);
  201. if (mActionCallback)
  202. {
  203. mActionCallback(speaker_id);
  204. }
  205. return true;
  206. }
  207. //
  208. // LLSpeakerMgr
  209. //
  210. LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :
  211. mVoiceChannel(channelp)
  212. , mVoiceModerated(false)
  213. , mModerateModeHandledFirstTime(false)
  214. {
  215. static LLUICachedControl<F32> remove_delay ("SpeakerParticipantRemoveDelay", 10.0);
  216. mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay);
  217. }
  218. LLSpeakerMgr::~LLSpeakerMgr()
  219. {
  220. delete mSpeakerDelayRemover;
  221. }
  222. LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
  223. {
  224. if (id.isNull()) return NULL;
  225. LLPointer<LLSpeaker> speakerp;
  226. if (mSpeakers.find(id) == mSpeakers.end())
  227. {
  228. speakerp = new LLSpeaker(id, name, type);
  229. speakerp->mStatus = status;
  230. mSpeakers.insert(std::make_pair(speakerp->mID, speakerp));
  231. mSpeakersSorted.push_back(speakerp);
  232. fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add");
  233. }
  234. else
  235. {
  236. speakerp = findSpeaker(id);
  237. if (speakerp.notNull())
  238. {
  239. // keep highest priority status (lowest value) instead of overriding current value
  240. speakerp->mStatus = llmin(speakerp->mStatus, status);
  241. // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id
  242. // we need to override speakers that we think are objects when we find out they are really
  243. // residents
  244. if (type == LLSpeaker::SPEAKER_AGENT)
  245. {
  246. speakerp->mType = LLSpeaker::SPEAKER_AGENT;
  247. speakerp->lookupName();
  248. }
  249. }
  250. }
  251. mSpeakerDelayRemover->unsetActionTimer(speakerp->mID);
  252. return speakerp;
  253. }
  254. // *TODO: Once way to request the current voice channel moderation mode is implemented
  255. // this method with related code should be removed.
  256. /*
  257. Initializes "moderate_mode" of voice session on first join.
  258. This is WORKAROUND because a way to request the current voice channel moderation mode exists
  259. but is not implemented in viewer yet. See EXT-6937.
  260. */
  261. void LLSpeakerMgr::initVoiceModerateMode()
  262. {
  263. if (!mModerateModeHandledFirstTime && (mVoiceChannel && mVoiceChannel->isActive()))
  264. {
  265. LLPointer<LLSpeaker> speakerp;
  266. if (mSpeakers.find(gAgentID) != mSpeakers.end())
  267. {
  268. speakerp = mSpeakers[gAgentID];
  269. }
  270. if (speakerp.notNull())
  271. {
  272. mVoiceModerated = speakerp->mModeratorMutedVoice;
  273. mModerateModeHandledFirstTime = true;
  274. }
  275. }
  276. }
  277. void LLSpeakerMgr::update(BOOL resort_ok)
  278. {
  279. if (!LLVoiceClient::getInstance())
  280. {
  281. return;
  282. }
  283. LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor");
  284. LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor");
  285. if(resort_ok) // only allow list changes when user is not interacting with it
  286. {
  287. updateSpeakerList();
  288. }
  289. // update status of all current speakers
  290. BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
  291. for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)
  292. {
  293. LLUUID speaker_id = speaker_it->first;
  294. LLSpeaker* speakerp = speaker_it->second;
  295. speaker_map_t::iterator cur_speaker_it = speaker_it++;
  296. if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id))
  297. {
  298. speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id);
  299. BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id);
  300. if (moderator_muted_voice != speakerp->mModeratorMutedVoice)
  301. {
  302. speakerp->mModeratorMutedVoice = moderator_muted_voice;
  303. speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp));
  304. }
  305. if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice)
  306. {
  307. speakerp->mStatus = LLSpeaker::STATUS_MUTED;
  308. }
  309. else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id))
  310. {
  311. // reset inactivity expiration
  312. if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING)
  313. {
  314. speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
  315. speakerp->mHasSpoken = TRUE;
  316. }
  317. speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
  318. // interpolate between active color and full speaking color based on power of speech output
  319. speakerp->mDotColor = speaking_color;
  320. if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL)
  321. {
  322. speakerp->mDotColor = overdriven_color;
  323. }
  324. }
  325. else
  326. {
  327. speakerp->mSpeechVolume = 0.f;
  328. speakerp->mDotColor = ACTIVE_COLOR;
  329. if (speakerp->mHasSpoken)
  330. {
  331. // have spoken once, not currently speaking
  332. speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN;
  333. }
  334. else
  335. {
  336. // default state for being in voice channel
  337. speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE;
  338. }
  339. }
  340. }
  341. // speaker no longer registered in voice channel, demote to text only
  342. else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL)
  343. {
  344. if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL)
  345. {
  346. // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice)
  347. speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
  348. }
  349. else
  350. {
  351. speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY;
  352. speakerp->mSpeechVolume = 0.f;
  353. speakerp->mDotColor = ACTIVE_COLOR;
  354. }
  355. }
  356. }
  357. if(resort_ok) // only allow list changes when user is not interacting with it
  358. {
  359. // sort by status then time last spoken
  360. std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers());
  361. }
  362. // for recent speakers who are not currently speaking, show "recent" color dot for most recent
  363. // fading to "active" color
  364. S32 recent_speaker_count = 0;
  365. S32 sort_index = 0;
  366. speaker_list_t::iterator sorted_speaker_it;
  367. for(sorted_speaker_it = mSpeakersSorted.begin();
  368. sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it)
  369. {
  370. LLPointer<LLSpeaker> speakerp = *sorted_speaker_it;
  371. // color code recent speakers who are not currently speaking
  372. if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN)
  373. {
  374. speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f));
  375. recent_speaker_count++;
  376. }
  377. // stuff sort ordinal into speaker so the ui can sort by this value
  378. speakerp->mSortIndex = sort_index++;
  379. }
  380. }
  381. void LLSpeakerMgr::updateSpeakerList()
  382. {
  383. // are we bound to the currently active voice channel?
  384. if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()))
  385. {
  386. std::set<LLUUID> participants;
  387. LLVoiceClient::getInstance()->getParticipantList(participants);
  388. // add new participants to our list of known speakers
  389. for (std::set<LLUUID>::iterator participant_it = participants.begin();
  390. participant_it != participants.end();
  391. ++participant_it)
  392. {
  393. setSpeaker(*participant_it,
  394. LLVoiceClient::getInstance()->getDisplayName(*participant_it),
  395. LLSpeaker::STATUS_VOICE_ACTIVE,
  396. (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL));
  397. }
  398. }
  399. }
  400. void LLSpeakerMgr::setSpeakerNotInChannel(LLSpeaker* speakerp)
  401. {
  402. speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
  403. speakerp->mDotColor = INACTIVE_COLOR;
  404. mSpeakerDelayRemover->setActionTimer(speakerp->mID);
  405. }
  406. bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id)
  407. {
  408. mSpeakers.erase(speaker_id);
  409. speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin();
  410. for(; sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it)
  411. {
  412. if (speaker_id == (*sorted_speaker_it)->mID)
  413. {
  414. mSpeakersSorted.erase(sorted_speaker_it);
  415. break;
  416. }
  417. }
  418. fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove");
  419. update(TRUE);
  420. return false;
  421. }
  422. LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id)
  423. {
  424. //In some conditions map causes crash if it is empty(Windows only), adding check (EK)
  425. if (mSpeakers.size() == 0)
  426. return NULL;
  427. speaker_map_t::iterator found_it = mSpeakers.find(speaker_id);
  428. if (found_it == mSpeakers.end())
  429. {
  430. return NULL;
  431. }
  432. return found_it->second;
  433. }
  434. void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text)
  435. {
  436. speaker_list->clear();
  437. for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
  438. {
  439. LLPointer<LLSpeaker> speakerp = speaker_it->second;
  440. // what about text only muted or inactive?
  441. if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY)
  442. {
  443. speaker_list->push_back(speakerp);
  444. }
  445. }
  446. }
  447. const LLUUID LLSpeakerMgr::getSessionID()
  448. {
  449. return mVoiceChannel->getSessionID();
  450. }
  451. void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing)
  452. {
  453. LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
  454. if (speakerp.notNull())
  455. {
  456. speakerp->mTyping = typing;
  457. }
  458. }
  459. // speaker has chatted via either text or voice
  460. void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
  461. {
  462. LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
  463. if (speakerp.notNull())
  464. {
  465. speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
  466. speakerp->mHasSpoken = TRUE;
  467. }
  468. }
  469. BOOL LLSpeakerMgr::isVoiceActive()
  470. {
  471. // mVoiceChannel = NULL means current voice channel, whatever it is
  472. return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();
  473. }
  474. //
  475. // LLIMSpeakerMgr
  476. //
  477. LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel)
  478. {
  479. }
  480. void LLIMSpeakerMgr::updateSpeakerList()
  481. {
  482. // don't do normal updates which are pulled from voice channel
  483. // rely on user list reported by sim
  484. // We need to do this to allow PSTN callers into group chats to show in the list.
  485. LLSpeakerMgr::updateSpeakerList();
  486. return;
  487. }
  488. void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers)
  489. {
  490. if ( !speakers.isMap() ) return;
  491. if ( speakers.has("agent_info") && speakers["agent_info"].isMap() )
  492. {
  493. LLSD::map_const_iterator speaker_it;
  494. for(speaker_it = speakers["agent_info"].beginMap();
  495. speaker_it != speakers["agent_info"].endMap();
  496. ++speaker_it)
  497. {
  498. LLUUID agent_id(speaker_it->first);
  499. LLPointer<LLSpeaker> speakerp = setSpeaker(
  500. agent_id,
  501. LLStringUtil::null,
  502. LLSpeaker::STATUS_TEXT_ONLY);
  503. if ( speaker_it->second.isMap() )
  504. {
  505. BOOL is_moderator = speakerp->mIsModerator;
  506. speakerp->mIsModerator = speaker_it->second["is_moderator"];
  507. speakerp->mModeratorMutedText =
  508. speaker_it->second["mutes"]["text"];
  509. // Fire event only if moderator changed
  510. if ( is_moderator != speakerp->mIsModerator )
  511. fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator");
  512. }
  513. }
  514. }
  515. else if ( speakers.has("agents" ) && speakers["agents"].isArray() )
  516. {
  517. //older, more decprecated way. Need here for
  518. //using older version of servers
  519. LLSD::array_const_iterator speaker_it;
  520. for(speaker_it = speakers["agents"].beginArray();
  521. speaker_it != speakers["agents"].endArray();
  522. ++speaker_it)
  523. {
  524. const LLUUID agent_id = (*speaker_it).asUUID();
  525. LLPointer<LLSpeaker> speakerp = setSpeaker(
  526. agent_id,
  527. LLStringUtil::null,
  528. LLSpeaker::STATUS_TEXT_ONLY);
  529. }
  530. }
  531. }
  532. void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
  533. {
  534. if ( !update.isMap() ) return;
  535. if ( update.has("agent_updates") && update["agent_updates"].isMap() )
  536. {
  537. LLSD::map_const_iterator update_it;
  538. for(
  539. update_it = update["agent_updates"].beginMap();
  540. update_it != update["agent_updates"].endMap();
  541. ++update_it)
  542. {
  543. LLUUID agent_id(update_it->first);
  544. LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
  545. LLSD agent_data = update_it->second;
  546. if (agent_data.isMap() && agent_data.has("transition"))
  547. {
  548. if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull())
  549. {
  550. setSpeakerNotInChannel(speakerp);
  551. }
  552. else if (agent_data["transition"].asString() == "ENTER")
  553. {
  554. // add or update speaker
  555. speakerp = setSpeaker(agent_id);
  556. }
  557. else
  558. {
  559. llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl;
  560. }
  561. }
  562. if (speakerp.isNull()) continue;
  563. // should have a valid speaker from this point on
  564. if (agent_data.isMap() && agent_data.has("info"))
  565. {
  566. LLSD agent_info = agent_data["info"];
  567. if (agent_info.has("is_moderator"))
  568. {
  569. BOOL is_moderator = speakerp->mIsModerator;
  570. speakerp->mIsModerator = agent_info["is_moderator"];
  571. // Fire event only if moderator changed
  572. if ( is_moderator != speakerp->mIsModerator )
  573. fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator");
  574. }
  575. if (agent_info.has("mutes"))
  576. {
  577. speakerp->mModeratorMutedText = agent_info["mutes"]["text"];
  578. }
  579. }
  580. }
  581. }
  582. else if ( update.has("updates") && update["updates"].isMap() )
  583. {
  584. LLSD::map_const_iterator update_it;
  585. for (
  586. update_it = update["updates"].beginMap();
  587. update_it != update["updates"].endMap();
  588. ++update_it)
  589. {
  590. LLUUID agent_id(update_it->first);
  591. LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
  592. std::string agent_transition = update_it->second.asString();
  593. if (agent_transition == "LEAVE" && speakerp.notNull())
  594. {
  595. setSpeakerNotInChannel(speakerp);
  596. }
  597. else if ( agent_transition == "ENTER")
  598. {
  599. // add or update speaker
  600. speakerp = setSpeaker(agent_id);
  601. }
  602. else
  603. {
  604. llwarns << "bad membership list update "
  605. << agent_transition << llendl;
  606. }
  607. }
  608. }
  609. }
  610. class ModerationResponder : public LLHTTPClient::Responder
  611. {
  612. public:
  613. ModerationResponder(const LLUUID& session_id)
  614. {
  615. mSessionID = session_id;
  616. }
  617. virtual void error(U32 status, const std::string& reason)
  618. {
  619. llwarns << status << ": " << reason << llendl;
  620. if ( gIMMgr )
  621. {
  622. //403 == you're not a mod
  623. //should be disabled if you're not a moderator
  624. if ( 403 == status )
  625. {
  626. gIMMgr->showSessionEventError(
  627. "mute",
  628. "not_a_mod_error",
  629. mSessionID);
  630. }
  631. else
  632. {
  633. gIMMgr->showSessionEventError(
  634. "mute",
  635. "generic_request_error",
  636. mSessionID);
  637. }
  638. }
  639. }
  640. private:
  641. LLUUID mSessionID;
  642. };
  643. void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)
  644. {
  645. LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
  646. if (!speakerp) return;
  647. std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
  648. LLSD data;
  649. data["method"] = "mute update";
  650. data["session-id"] = getSessionID();
  651. data["params"] = LLSD::emptyMap();
  652. data["params"]["agent_id"] = speaker_id;
  653. data["params"]["mute_info"] = LLSD::emptyMap();
  654. //current value represents ability to type, so invert
  655. data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText;
  656. LLHTTPClient::post(url, data, new ModerationResponder(getSessionID()));
  657. }
  658. void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute)
  659. {
  660. LLPointer<LLSpeaker> speakerp = findSpeaker(avatar_id);
  661. if (!speakerp) return;
  662. // *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for
  663. // text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE)
  664. bool is_in_voice = speakerp->mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || speakerp->mStatus == LLSpeaker::STATUS_MUTED;
  665. // do not send voice moderation changes for avatars not in voice channel
  666. if (!is_in_voice) return;
  667. std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
  668. LLSD data;
  669. data["method"] = "mute update";
  670. data["session-id"] = getSessionID();
  671. data["params"] = LLSD::emptyMap();
  672. data["params"]["agent_id"] = avatar_id;
  673. data["params"]["mute_info"] = LLSD::emptyMap();
  674. data["params"]["mute_info"]["voice"] = !unmute;
  675. LLHTTPClient::post(
  676. url,
  677. data,
  678. new ModerationResponder(getSessionID()));
  679. }
  680. void LLIMSpeakerMgr::moderateVoiceAllParticipants( bool unmute_everyone )
  681. {
  682. if (mVoiceModerated == !unmute_everyone)
  683. {
  684. // session already in requested state. Just force participants which do not match it.
  685. forceVoiceModeratedMode(mVoiceModerated);
  686. }
  687. else
  688. {
  689. // otherwise set moderated mode for a whole session.
  690. moderateVoiceSession(getSessionID(), !unmute_everyone);
  691. }
  692. }
  693. void LLIMSpeakerMgr::processSessionUpdate(const LLSD& session_update)
  694. {
  695. if (session_update.has("moderated_mode") &&
  696. session_update["moderated_mode"].has("voice"))
  697. {
  698. mVoiceModerated = session_update["moderated_mode"]["voice"];
  699. }
  700. }
  701. void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallow_voice)
  702. {
  703. std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
  704. LLSD data;
  705. data["method"] = "session update";
  706. data["session-id"] = session_id;
  707. data["params"] = LLSD::emptyMap();
  708. data["params"]["update_info"] = LLSD::emptyMap();
  709. data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap();
  710. data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice;
  711. LLHTTPClient::post(url, data, new ModerationResponder(session_id));
  712. }
  713. void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted)
  714. {
  715. for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
  716. {
  717. LLUUID speaker_id = speaker_it->first;
  718. LLSpeaker* speakerp = speaker_it->second;
  719. // participant does not match requested state
  720. if (should_be_muted != (bool)speakerp->mModeratorMutedVoice)
  721. {
  722. moderateVoiceParticipant(speaker_id, !should_be_muted);
  723. }
  724. }
  725. }
  726. //
  727. // LLActiveSpeakerMgr
  728. //
  729. LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL)
  730. {
  731. }
  732. void LLActiveSpeakerMgr::updateSpeakerList()
  733. {
  734. // point to whatever the current voice channel is
  735. mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
  736. // always populate from active voice channel
  737. if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false
  738. {
  739. fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear");
  740. mSpeakers.clear();
  741. mSpeakersSorted.clear();
  742. mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
  743. mSpeakerDelayRemover->removeAllTimers();
  744. }
  745. LLSpeakerMgr::updateSpeakerList();
  746. // clean up text only speakers
  747. for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
  748. {
  749. LLUUID speaker_id = speaker_it->first;
  750. LLSpeaker* speakerp = speaker_it->second;
  751. if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
  752. {
  753. // automatically flag text only speakers for removal
  754. speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
  755. }
  756. }
  757. }
  758. //
  759. // LLLocalSpeakerMgr
  760. //
  761. LLLocalSpeakerMgr::LLLocalSpeakerMgr() : LLSpeakerMgr(LLVoiceChannelProximal::getInstance())
  762. {
  763. }
  764. LLLocalSpeakerMgr::~LLLocalSpeakerMgr ()
  765. {
  766. }
  767. void LLLocalSpeakerMgr::updateSpeakerList()
  768. {
  769. // pull speakers from voice channel
  770. LLSpeakerMgr::updateSpeakerList();
  771. if (gDisconnected)//the world is cleared.
  772. {
  773. return ;
  774. }
  775. // pick up non-voice speakers in chat range
  776. uuid_vec_t avatar_ids;
  777. std::vector<LLVector3d> positions;
  778. LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS);
  779. for(U32 i=0; i<avatar_ids.size(); i++)
  780. {
  781. setSpeaker(avatar_ids[i]);
  782. }
  783. // check if text only speakers have moved out of chat range
  784. for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
  785. {
  786. LLUUID speaker_id = speaker_it->first;
  787. LLSpeaker* speakerp = speaker_it->second;
  788. if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
  789. {
  790. LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id);
  791. if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS_SQUARED)
  792. {
  793. setSpeakerNotInChannel(speakerp);
  794. }
  795. }
  796. }
  797. }