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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llcallfloater.cpp
  3.  * @author Mike Antipov
  4.  * @brief Voice Control Panel in a Voice Chats (P2P, Group, Nearby...).
  5.  *
  6.  * $LicenseInfo:firstyear=2009&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2009-2010, Linden Research, Inc.
  9.  * 
  10.  * Second Life Viewer Source Code
  11.  * The source code in this file ("Source Code") is provided by Linden Lab
  12.  * to you under the terms of the GNU General Public License, version 2.0
  13.  * ("GPL"), unless you have obtained a separate licensing agreement
  14.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  15.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17.  * 
  18.  * There are special exceptions to the terms and conditions of the GPL as
  19.  * it is applied to this Source Code. View the full text of the exception
  20.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  21.  * online at
  22.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23.  * 
  24.  * By copying, modifying or distributing this software, you acknowledge
  25.  * that you have read and understood your obligations described above,
  26.  * and agree to abide by those obligations.
  27.  * 
  28.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30.  * COMPLETENESS OR PERFORMANCE.
  31.  * $/LicenseInfo$
  32.  */
  33. #include "llviewerprecompiledheaders.h"
  34. #include "llnotificationsutil.h"
  35. #include "lltrans.h"
  36. #include "llcallfloater.h"
  37. #include "llagent.h"
  38. #include "llagentdata.h" // for gAgentID
  39. #include "llavatariconctrl.h"
  40. #include "llavatarlist.h"
  41. #include "llbottomtray.h"
  42. #include "lldraghandle.h"
  43. #include "llimfloater.h"
  44. #include "llfloaterreg.h"
  45. #include "llparticipantlist.h"
  46. #include "llspeakers.h"
  47. #include "lltextutil.h"
  48. #include "lltransientfloatermgr.h"
  49. #include "llviewerwindow.h"
  50. #include "llvoicechannel.h"
  51. #include "llviewerparcelmgr.h"
  52. static void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids);
  53. void reshape_floater(LLCallFloater* floater, S32 delta_height);
  54. class LLNonAvatarCaller : public LLAvatarListItem
  55. {
  56. public:
  57. LLNonAvatarCaller() : LLAvatarListItem(false)
  58. {
  59. }
  60. BOOL postBuild()
  61. {
  62. BOOL rv = LLAvatarListItem::postBuild();
  63. if (rv)
  64. {
  65. setOnline(true);
  66. showLastInteractionTime(false);
  67. setShowProfileBtn(false);
  68. setShowInfoBtn(false);
  69. mAvatarIcon->setValue("Avaline_Icon");
  70. mAvatarIcon->setToolTip(std::string(""));
  71. }
  72. return rv;
  73. }
  74. void setName(const std::string& name)
  75. {
  76. const std::string& formatted_phone = LLTextUtil::formatPhoneNumber(name);
  77. LLAvatarListItem::setName(formatted_phone);
  78. }
  79. void setSpeakerId(const LLUUID& id) { mSpeakingIndicator->setSpeakerId(id); }
  80. };
  81. static void* create_non_avatar_caller(void*)
  82. {
  83. return new LLNonAvatarCaller;
  84. }
  85. LLVoiceChannel* LLCallFloater::sCurrentVoiceCanel = NULL;
  86. LLCallFloater::LLCallFloater(const LLSD& key)
  87. : LLTransientDockableFloater(NULL, false, key)
  88. , mSpeakerManager(NULL)
  89. , mParticipants(NULL)
  90. , mAvatarList(NULL)
  91. , mNonAvatarCaller(NULL)
  92. , mVoiceType(VC_LOCAL_CHAT)
  93. , mAgentPanel(NULL)
  94. , mSpeakingIndicator(NULL)
  95. , mIsModeratorMutedVoice(false)
  96. , mInitParticipantsVoiceState(false)
  97. {
  98. static LLUICachedControl<S32> voice_left_remove_delay ("VoiceParticipantLeftRemoveDelay", 10);
  99. mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), voice_left_remove_delay);
  100. mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL);
  101. LLVoiceClient::getInstance()->addObserver(this);
  102. LLTransientFloaterMgr::getInstance()->addControlView(this);
  103. }
  104. LLCallFloater::~LLCallFloater()
  105. {
  106. resetVoiceRemoveTimers();
  107. delete mSpeakerDelayRemover;
  108. delete mParticipants;
  109. mParticipants = NULL;
  110. mAvatarListRefreshConnection.disconnect();
  111. mVoiceChannelStateChangeConnection.disconnect();
  112. // Don't use LLVoiceClient::getInstance() here 
  113. // singleton MAY have already been destroyed.
  114. if(gVoiceClient)
  115. {
  116. gVoiceClient->removeObserver(this);
  117. }
  118. LLTransientFloaterMgr::getInstance()->removeControlView(this);
  119. }
  120. // virtual
  121. BOOL LLCallFloater::postBuild()
  122. {
  123. LLTransientDockableFloater::postBuild();
  124. mAvatarList = getChild<LLAvatarList>("speakers_list");
  125. mAvatarListRefreshConnection = mAvatarList->setRefreshCompleteCallback(boost::bind(&LLCallFloater::onAvatarListRefreshed, this));
  126. childSetAction("leave_call_btn", boost::bind(&LLCallFloater::leaveCall, this));
  127. mNonAvatarCaller = getChild<LLNonAvatarCaller>("non_avatar_caller");
  128. mNonAvatarCaller->setVisible(FALSE);
  129. LLView *anchor_panel = LLBottomTray::getInstance()->getChild<LLView>("speak_flyout_btn");
  130. setDockControl(new LLDockControl(
  131. anchor_panel, this,
  132. getDockTongue(), LLDockControl::TOP));
  133. initAgentData();
  134. connectToChannel(LLVoiceChannel::getCurrentVoiceChannel());
  135. setIsChrome(true);
  136. //chrome="true" hides floater caption 
  137. if (mDragHandle)
  138. mDragHandle->setTitleVisible(TRUE);
  139. updateSession();
  140. return TRUE;
  141. }
  142. // virtual
  143. void LLCallFloater::onOpen(const LLSD& /*key*/)
  144. {
  145. }
  146. // virtual
  147. void LLCallFloater::draw()
  148. {
  149. // we have to refresh participants to display ones not in voice as disabled.
  150. // It should be done only when she joins or leaves voice chat.
  151. // But seems that LLVoiceClientParticipantObserver is not enough to satisfy this requirement.
  152. // *TODO: mantipov: remove from draw()
  153. // NOTE: it looks like calling onChange() here is not necessary,
  154. // but sometime it is not called properly from the observable object.
  155. // Seems this is a problem somewhere in Voice Client (LLVoiceClient::participantAddedEvent)
  156. // onChange();
  157. bool is_moderator_muted = gVoiceClient->getIsModeratorMuted(gAgentID);
  158. if (mIsModeratorMutedVoice != is_moderator_muted)
  159. {
  160. setModeratorMutedVoice(is_moderator_muted);
  161. }
  162. // Need to resort the participant list if it's in sort by recent speaker order.
  163. if (mParticipants)
  164. mParticipants->updateRecentSpeakersOrder();
  165. LLTransientDockableFloater::draw();
  166. }
  167. // virtual
  168. void LLCallFloater::onChange()
  169. {
  170. if (NULL == mParticipants) return;
  171. updateParticipantsVoiceState();
  172. // Add newly joined participants.
  173. std::vector<LLUUID> speakers_uuids;
  174. get_voice_participants_uuids(speakers_uuids);
  175. for (std::vector<LLUUID>::const_iterator it = speakers_uuids.begin(); it != speakers_uuids.end(); it++)
  176. {
  177. mParticipants->addAvatarIDExceptAgent(*it);
  178. }
  179. }
  180. //////////////////////////////////////////////////////////////////////////
  181. /// PRIVATE SECTION
  182. //////////////////////////////////////////////////////////////////////////
  183. void LLCallFloater::leaveCall()
  184. {
  185. LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();
  186. if (voice_channel)
  187. {
  188. voice_channel->deactivate();
  189. }
  190. }
  191. void LLCallFloater::updateSession()
  192. {
  193. LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();
  194. if (voice_channel)
  195. {
  196. lldebugs << "Current voice channel: " << voice_channel->getSessionID() << llendl;
  197. if (mSpeakerManager && voice_channel->getSessionID() == mSpeakerManager->getSessionID())
  198. {
  199. lldebugs << "Speaker manager is already set for session: " << voice_channel->getSessionID() << llendl;
  200. return;
  201. }
  202. else
  203. {
  204. mSpeakerManager = NULL;
  205. }
  206. }
  207. const LLUUID& session_id = voice_channel ? voice_channel->getSessionID() : LLUUID::null;
  208. lldebugs << "Set speaker manager for session: " << session_id << llendl;
  209. LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id);
  210. if (im_session)
  211. {
  212. mSpeakerManager = LLIMModel::getInstance()->getSpeakerManager(session_id);
  213. switch (im_session->mType)
  214. {
  215. case IM_NOTHING_SPECIAL:
  216. case IM_SESSION_P2P_INVITE:
  217. mVoiceType = VC_PEER_TO_PEER;
  218. if (!im_session->mOtherParticipantIsAvatar)
  219. {
  220. mVoiceType = VC_PEER_TO_PEER_AVALINE;
  221. }
  222. break;
  223. case IM_SESSION_CONFERENCE_START:
  224. case IM_SESSION_GROUP_START:
  225. case IM_SESSION_INVITE:
  226. if (gAgent.isInGroup(session_id))
  227. {
  228. mVoiceType = VC_GROUP_CHAT;
  229. }
  230. else
  231. {
  232. mVoiceType = VC_AD_HOC_CHAT;
  233. }
  234. break;
  235. default:
  236. llwarning("Failed to determine voice call IM type", 0);
  237. mVoiceType = VC_GROUP_CHAT;
  238. break;
  239. }
  240. }
  241. if (NULL == mSpeakerManager)
  242. {
  243. // by default let show nearby chat participants
  244. mSpeakerManager = LLLocalSpeakerMgr::getInstance();
  245. lldebugs << "Set DEFAULT speaker manager" << llendl;
  246. mVoiceType = VC_LOCAL_CHAT;
  247. }
  248. updateTitle();
  249. //hide "Leave Call" button for nearby chat
  250. bool is_local_chat = mVoiceType == VC_LOCAL_CHAT;
  251. childSetVisible("leave_call_btn_panel", !is_local_chat);
  252. refreshParticipantList();
  253. updateAgentModeratorState();
  254. //show floater for voice calls & only in CONNECTED to voice channel state
  255. if (!is_local_chat &&
  256.     voice_channel &&
  257.     LLVoiceChannel::STATE_CONNECTED == voice_channel->getState())
  258. {
  259. LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
  260. bool show_me = !(im_floater && im_floater->getVisible());
  261. if (show_me) 
  262. {
  263. setVisible(true);
  264. }
  265. }
  266. }
  267. void LLCallFloater::refreshParticipantList()
  268. {
  269. bool non_avatar_caller = VC_PEER_TO_PEER_AVALINE == mVoiceType;
  270. if (non_avatar_caller)
  271. {
  272. LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSpeakerManager->getSessionID());
  273. mNonAvatarCaller->setSpeakerId(session->mOtherParticipantID);
  274. mNonAvatarCaller->setName(session->mName);
  275. }
  276. mNonAvatarCaller->setVisible(non_avatar_caller);
  277. mAvatarList->setVisible(!non_avatar_caller);
  278. if (!non_avatar_caller)
  279. {
  280. mParticipants = new LLParticipantList(mSpeakerManager, mAvatarList, true, mVoiceType != VC_GROUP_CHAT && mVoiceType != VC_AD_HOC_CHAT);
  281. mParticipants->setValidateSpeakerCallback(boost::bind(&LLCallFloater::validateSpeaker, this, _1));
  282. mParticipants->setSortOrder(LLParticipantList::E_SORT_BY_RECENT_SPEAKERS);
  283. if (LLLocalSpeakerMgr::getInstance() == mSpeakerManager)
  284. {
  285. mAvatarList->setNoItemsCommentText(getString("no_one_near"));
  286. }
  287. // we have to made delayed initialization of voice state of participant list.
  288. // it will be performed after first LLAvatarList refreshing in the onAvatarListRefreshed().
  289. mInitParticipantsVoiceState = true;
  290. }
  291. }
  292. void LLCallFloater::onAvatarListRefreshed()
  293. {
  294. if (mInitParticipantsVoiceState)
  295. {
  296. initParticipantsVoiceState();
  297. mInitParticipantsVoiceState = false;
  298. }
  299. else
  300. {
  301. updateParticipantsVoiceState();
  302. }
  303. }
  304. // static
  305. void LLCallFloater::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)
  306. {
  307. LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel();
  308. // *NOTE: if signal was sent for voice channel with LLVoiceChannel::STATE_NO_CHANNEL_INFO
  309. // it sill be sent for the same channel again (when state is changed).
  310. // So, lets ignore this call.
  311. if (channel == sCurrentVoiceCanel) return;
  312. LLCallFloater* call_floater = LLFloaterReg::getTypedInstance<LLCallFloater>("voice_controls");
  313. call_floater->connectToChannel(channel);
  314. }
  315. void LLCallFloater::updateTitle()
  316. {
  317. LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();
  318. std::string title;
  319. switch (mVoiceType)
  320. {
  321. case VC_LOCAL_CHAT:
  322. title = getString("title_nearby");
  323. break;
  324. case VC_PEER_TO_PEER:
  325. case VC_PEER_TO_PEER_AVALINE:
  326. {
  327. title = voice_channel->getSessionName();
  328. if (VC_PEER_TO_PEER_AVALINE == mVoiceType)
  329. {
  330. title = LLTextUtil::formatPhoneNumber(title);
  331. }
  332. LLStringUtil::format_map_t args;
  333. args["[NAME]"] = title;
  334. title = getString("title_peer_2_peer", args);
  335. }
  336. break;
  337. case VC_AD_HOC_CHAT:
  338. title = getString("title_adhoc");
  339. break;
  340. case VC_GROUP_CHAT:
  341. {
  342. LLStringUtil::format_map_t args;
  343. args["[GROUP]"] = voice_channel->getSessionName();
  344. title = getString("title_group", args);
  345. }
  346. break;
  347. }
  348. setTitle(title);
  349. }
  350. void LLCallFloater::initAgentData()
  351. {
  352. mAgentPanel = getChild<LLPanel> ("my_panel");
  353. if ( mAgentPanel )
  354. {
  355. mAgentPanel->childSetValue("user_icon", gAgentID);
  356. std::string name;
  357. gCacheName->getFullName(gAgentID, name);
  358. mAgentPanel->childSetValue("user_text", name);
  359. mSpeakingIndicator = mAgentPanel->getChild<LLOutputMonitorCtrl>("speaking_indicator");
  360. mSpeakingIndicator->setSpeakerId(gAgentID);
  361. }
  362. }
  363. void LLCallFloater::setModeratorMutedVoice(bool moderator_muted)
  364. {
  365. mIsModeratorMutedVoice = moderator_muted;
  366. if (moderator_muted)
  367. {
  368. LLNotificationsUtil::add("VoiceIsMutedByModerator");
  369. }
  370. mSpeakingIndicator->setIsMuted(moderator_muted);
  371. }
  372. void LLCallFloater::updateAgentModeratorState()
  373. {
  374. std::string name;
  375. gCacheName->getFullName(gAgentID, name);
  376. if(gAgent.isInGroup(mSpeakerManager->getSessionID()))
  377. {
  378. // This method can be called when LLVoiceChannel.mState == STATE_NO_CHANNEL_INFO
  379. // in this case there are no any speakers yet.
  380. if (mSpeakerManager->findSpeaker(gAgentID))
  381. {
  382. // Agent is Moderator
  383. if (mSpeakerManager->findSpeaker(gAgentID)->mIsModerator)
  384. {
  385. const std::string moderator_indicator(LLTrans::getString("IM_moderator_label")); 
  386. name += " " + moderator_indicator;
  387. }
  388. }
  389. }
  390. mAgentPanel->childSetValue("user_text", name);
  391. }
  392. static void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids)
  393. {
  394. // Get a list of participants from VoiceClient
  395. LLVoiceClient::participantMap *voice_map = gVoiceClient->getParticipantList();
  396. if (voice_map)
  397. {
  398. for (LLVoiceClient::participantMap::const_iterator iter = voice_map->begin();
  399. iter != voice_map->end(); ++iter)
  400. {
  401. LLUUID id = (*iter).second->mAvatarID;
  402. speakers_uuids.push_back(id);
  403. }
  404. }
  405. }
  406. void LLCallFloater::initParticipantsVoiceState()
  407. {
  408. // Set initial status for each participant in the list.
  409. std::vector<LLPanel*> items;
  410. mAvatarList->getItems(items);
  411. std::vector<LLPanel*>::const_iterator
  412. it = items.begin(),
  413. it_end = items.end();
  414. std::vector<LLUUID> speakers_uuids;
  415. get_voice_participants_uuids(speakers_uuids);
  416. for(; it != it_end; ++it)
  417. {
  418. LLAvatarListItem *item = dynamic_cast<LLAvatarListItem*>(*it);
  419. if (!item) continue;
  420. LLUUID speaker_id = item->getAvatarId();
  421. std::vector<LLUUID>::const_iterator speaker_iter = std::find(speakers_uuids.begin(), speakers_uuids.end(), speaker_id);
  422. // If an avatarID assigned to a panel is found in a speakers list
  423. // obtained from VoiceClient we assign the JOINED status to the owner
  424. // of this avatarID.
  425. if (speaker_iter != speakers_uuids.end())
  426. {
  427. setState(item, STATE_JOINED);
  428. }
  429. else
  430. {
  431. LLPointer<LLSpeaker> speakerp = mSpeakerManager->findSpeaker(speaker_id);
  432. // If someone has already left the call before, we create his
  433. // avatar row panel with HAS_LEFT status and remove it after
  434. // the timeout, otherwise we create a panel with INVITED status
  435. if (speakerp.notNull() && speakerp.get()->mHasLeftCurrentCall)
  436. {
  437. setState(item, STATE_LEFT);
  438. }
  439. else
  440. {
  441. setState(item, STATE_INVITED);
  442. }
  443. }
  444. }
  445. }
  446. void LLCallFloater::updateParticipantsVoiceState()
  447. {
  448. std::vector<LLUUID> speakers_list;
  449. // Get a list of participants from VoiceClient
  450. std::vector<LLUUID> speakers_uuids;
  451. get_voice_participants_uuids(speakers_uuids);
  452. // Updating the status for each participant already in list.
  453. std::vector<LLPanel*> items;
  454. mAvatarList->getItems(items);
  455. std::vector<LLPanel*>::const_iterator
  456. it = items.begin(),
  457. it_end = items.end();
  458. for(; it != it_end; ++it)
  459. {
  460. LLAvatarListItem *item = dynamic_cast<LLAvatarListItem*>(*it);
  461. if (!item) continue;
  462. const LLUUID participant_id = item->getAvatarId();
  463. bool found = false;
  464. std::vector<LLUUID>::iterator speakers_iter = std::find(speakers_uuids.begin(), speakers_uuids.end(), participant_id);
  465. lldebugs << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << llendl;
  466. // If an avatarID assigned to a panel is found in a speakers list
  467. // obtained from VoiceClient we assign the JOINED status to the owner
  468. // of this avatarID.
  469. if (speakers_iter != speakers_uuids.end())
  470. {
  471. setState(item, STATE_JOINED);
  472. LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(participant_id);
  473. if (speaker.isNull())
  474. continue;
  475. speaker->mHasLeftCurrentCall = FALSE;
  476. speakers_uuids.erase(speakers_iter);
  477. found = true;
  478. }
  479. if (!found)
  480. {
  481. updateNotInVoiceParticipantState(item);
  482. }
  483. }
  484. }
  485. void LLCallFloater::updateNotInVoiceParticipantState(LLAvatarListItem* item)
  486. {
  487. LLUUID participant_id = item->getAvatarId();
  488. ESpeakerState current_state = getState(participant_id);
  489. switch (current_state)
  490. {
  491. case STATE_JOINED:
  492. // If an avatarID is not found in a speakers list from VoiceClient and
  493. // a panel with this ID has a JOINED status this means that this person
  494. // HAS LEFT the call.
  495. setState(item, STATE_LEFT);
  496. {
  497. LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(participant_id);
  498. if (speaker.notNull())
  499. {
  500. speaker->mHasLeftCurrentCall = TRUE;
  501. }
  502. }
  503. break;
  504. case STATE_INVITED:
  505. case STATE_LEFT:
  506. // nothing to do. These states should not be changed.
  507. break;
  508. case STATE_UNKNOWN:
  509. // If an avatarID is not found in a speakers list from VoiceClient and
  510. // a panel with this ID has an UNKNOWN status this means that this person
  511. // HAS ENTERED session but it is not in voice chat yet. So, set INVITED status
  512. setState(item, STATE_INVITED);
  513. break;
  514. default:
  515. // for possible new future states.
  516. llwarns << "Unsupported (" << getState(participant_id) << ") state for: " << item->getAvatarName()  << llendl;
  517. break;
  518. }
  519. }
  520. void LLCallFloater::setState(LLAvatarListItem* item, ESpeakerState state)
  521. {
  522. // *HACK: mantipov: sometimes such situation is possible while switching to voice channel:
  523. /*
  524. - voice channel is switched to the one user is joining
  525. - participant list is initialized with voice states: agent is in voice
  526. - than such log messages were found (with agent UUID)
  527. - LLVivoxProtocolParser::process_impl: parsing: <Response requestId="22" action="Session.MediaDisconnect.1"><ReturnCode>0</ReturnCode><Results><StatusCode>0</StatusCode><StatusString /></Results><InputXml><Request requestId="22" action="Session.MediaDisconnect.1"><SessionGroupHandle>9</SessionGroupHandle><SessionHandle>12</SessionHandle><Media>Audio</Media></Request></InputXml></Response>
  528. - LLVoiceClient::sessionState::removeParticipant: participant "sip:x2pwNkMbpR_mK4rtB_awASA==@bhr.vivox.com" (da9c0d90-c6e9-47f9-8ae2-bb41fdac0048) removed.
  529. - and than while updating participants voice states agent is marked as HAS LEFT
  530. - next updating of LLVoiceClient state makes agent JOINED
  531. So, lets skip HAS LEFT state for agent's avatar
  532. */
  533. if (STATE_LEFT == state && item->getAvatarId() == gAgentID) return;
  534. setState(item->getAvatarId(), state);
  535. switch (state)
  536. {
  537. case STATE_INVITED:
  538. item->setState(LLAvatarListItem::IS_VOICE_INVITED);
  539. break;
  540. case STATE_JOINED:
  541. removeVoiceRemoveTimer(item->getAvatarId());
  542. item->setState(LLAvatarListItem::IS_VOICE_JOINED);
  543. break;
  544. case STATE_LEFT:
  545. {
  546. setVoiceRemoveTimer(item->getAvatarId());
  547. item->setState(LLAvatarListItem::IS_VOICE_LEFT);
  548. }
  549. break;
  550. default:
  551. llwarns << "Unrecognized avatar panel state (" << state << ")" << llendl;
  552. break;
  553. }
  554. }
  555. void LLCallFloater::setVoiceRemoveTimer(const LLUUID& voice_speaker_id)
  556. {
  557. mSpeakerDelayRemover->setActionTimer(voice_speaker_id);
  558. }
  559. bool LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id)
  560. {
  561. LLAvatarList::uuid_vector_t& speaker_uuids = mAvatarList->getIDs();
  562. LLAvatarList::uuid_vector_t::iterator pos = std::find(speaker_uuids.begin(), speaker_uuids.end(), voice_speaker_id);
  563. if(pos != speaker_uuids.end())
  564. {
  565. speaker_uuids.erase(pos);
  566. mAvatarList->setDirty();
  567. }
  568. return false;
  569. }
  570. void LLCallFloater::resetVoiceRemoveTimers()
  571. {
  572. mSpeakerDelayRemover->removeAllTimers();
  573. }
  574. void LLCallFloater::removeVoiceRemoveTimer(const LLUUID& voice_speaker_id)
  575. {
  576. mSpeakerDelayRemover->unsetActionTimer(voice_speaker_id);
  577. }
  578. bool LLCallFloater::validateSpeaker(const LLUUID& speaker_id)
  579. {
  580. bool is_valid = true;
  581. switch (mVoiceType)
  582. {
  583. case  VC_LOCAL_CHAT:
  584. {
  585. // A nearby chat speaker is considered valid it it's known to LLVoiceClient (i.e. has enabled voice).
  586. std::vector<LLUUID> speakers;
  587. get_voice_participants_uuids(speakers);
  588. is_valid = std::find(speakers.begin(), speakers.end(), speaker_id) != speakers.end();
  589. }
  590. break;
  591. case VC_GROUP_CHAT:
  592. // if participant had left this call before do not allow add her again. See EXT-4216.
  593. // but if she Join she will be added into the list from the LLCallFloater::onChange()
  594. is_valid = STATE_LEFT != getState(speaker_id);
  595. break;
  596. default:
  597. // do nothing. required for Linux build
  598. break;
  599. }
  600. return is_valid;
  601. }
  602. void LLCallFloater::connectToChannel(LLVoiceChannel* channel)
  603. {
  604. mVoiceChannelStateChangeConnection.disconnect();
  605. sCurrentVoiceCanel = channel;
  606. mVoiceChannelStateChangeConnection = sCurrentVoiceCanel->setStateChangedCallback(boost::bind(&LLCallFloater::onVoiceChannelStateChanged, this, _1, _2));
  607. updateState(channel->getState());
  608. }
  609. void LLCallFloater::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state)
  610. {
  611. // check is voice operational and if it doesn't work hide VCP (EXT-4397)
  612. if(LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking())
  613. {
  614. updateState(new_state);
  615. }
  616. else
  617. {
  618. closeFloater();
  619. }
  620. }
  621. void LLCallFloater::updateState(const LLVoiceChannel::EState& new_state)
  622. {
  623. LL_DEBUGS("Voice") << "Updating state: " << new_state << ", session name: " << sCurrentVoiceCanel->getSessionName() << LL_ENDL;
  624. if (LLVoiceChannel::STATE_CONNECTED == new_state)
  625. {
  626. updateSession();
  627. }
  628. else
  629. {
  630. reset(new_state);
  631. }
  632. }
  633. void LLCallFloater::reset(const LLVoiceChannel::EState& new_state)
  634. {
  635. // lets forget states from the previous session
  636. // for timers...
  637. resetVoiceRemoveTimers();
  638. // ...and for speaker state
  639. mSpeakerStateMap.clear();
  640. delete mParticipants;
  641. mParticipants = NULL;
  642. mAvatarList->clear();
  643. // These ifs were added instead of simply showing "loading" to make VCP work correctly in parcels
  644. // with disabled voice (EXT-4648 and EXT-4649)
  645. if (!LLViewerParcelMgr::getInstance()->allowAgentVoice() && LLVoiceChannel::STATE_HUNG_UP == new_state)
  646. {
  647. // hides "Leave Call" when call is ended in parcel with disabled voice- hiding usually happens in
  648. // updateSession() which won't be called here because connect to nearby voice never happens 
  649. childSetVisible("leave_call_btn_panel", false);
  650. // setting title to nearby chat an "no one near..." text- because in region with disabled
  651. // voice we won't have chance to really connect to nearby, so VCP is changed here manually
  652. setTitle(getString("title_nearby"));
  653. mAvatarList->setNoItemsCommentText(getString("no_one_near"));
  654. }
  655. // "loading" is shown  only when state is "ringing" to avoid showing it in nearby chat vcp
  656. // of parcels with disabled voice all the time- "no_one_near" is now shown there (EXT-4648)
  657. else if (new_state == LLVoiceChannel::STATE_RINGING)
  658. {
  659. // update floater to show Loading while waiting for data.
  660. mAvatarList->setNoItemsCommentText(LLTrans::getString("LoadingData"));
  661. }
  662. mAvatarList->setVisible(TRUE);
  663. mNonAvatarCaller->setVisible(FALSE);
  664. mSpeakerManager = NULL;
  665. }
  666. //EOF