llfloateractivespeakers.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llfloateractivespeakers.h"
00035 
00036 #include "llagent.h"
00037 #include "llvoavatar.h"
00038 #include "llfloateravatarinfo.h"
00039 #include "lluictrlfactory.h"
00040 #include "llviewercontrol.h"
00041 #include "llscrolllistctrl.h"
00042 #include "llbutton.h"
00043 #include "lltextbox.h"
00044 #include "llmutelist.h"
00045 #include "llviewerobjectlist.h"
00046 #include "llimpanel.h" // LLVoiceChannel
00047 #include "llsdutil.h"
00048 #include "llimview.h"
00049 
00050 const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers
00051 const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f);
00052 const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f);
00053 const F32 TYPING_ANIMATION_FPS = 2.5f;
00054 
00055 LLSpeaker::LLSpeaker(const LLUUID& id, const LLString& name, const ESpeakerType type) : 
00056         mStatus(LLSpeaker::STATUS_TEXT_ONLY),
00057         mLastSpokeTime(0.f), 
00058         mSpeechVolume(0.f), 
00059         mHasSpoken(FALSE),
00060         mDotColor(LLColor4::white),
00061         mID(id),
00062         mTyping(FALSE),
00063         mSortIndex(0),
00064         mType(type),
00065         mIsModerator(FALSE),
00066         mModeratorMutedVoice(FALSE),
00067         mModeratorMutedText(FALSE)
00068 {
00069         if (name.empty() && type == SPEAKER_AGENT)
00070         {
00071                 lookupName();
00072         }
00073         else
00074         {
00075                 mDisplayName = name;
00076         }
00077 
00078         gVoiceClient->setUserVolume(id, LLMuteList::getInstance()->getSavedResidentVolume(id));
00079 
00080         mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
00081 }
00082 
00083 
00084 void LLSpeaker::lookupName()
00085 {
00086         gCacheName->getName(mID, onAvatarNameLookup, new LLHandle<LLSpeaker>(getHandle()));
00087 }
00088 
00089 //static 
00090 void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* user_data)
00091 {
00092         LLSpeaker* speaker_ptr = ((LLHandle<LLSpeaker>*)user_data)->get();
00093         delete (LLHandle<LLSpeaker>*)user_data;
00094 
00095         if (speaker_ptr)
00096         {
00097                 speaker_ptr->mDisplayName = llformat("%s %s", first, last);
00098         }
00099 }
00100 
00101 LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source)
00102 : LLEvent(source, "Speaker text moderation event")
00103 {
00104 }
00105 
00106 LLSD LLSpeakerTextModerationEvent::getValue()
00107 {
00108         return LLString("text");
00109 }
00110 
00111 
00112 LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source)
00113 : LLEvent(source, "Speaker voice moderation event")
00114 {
00115 }
00116 
00117 LLSD LLSpeakerVoiceModerationEvent::getValue()
00118 {
00119         return LLString("voice");
00120 }
00121 
00122 LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id)
00123 : LLEvent(source, "Speaker added/removed from speaker mgr"),
00124   mSpeakerID(speaker_id)
00125 {
00126 }
00127 
00128 LLSD LLSpeakerListChangeEvent::getValue()
00129 {
00130         return mSpeakerID;
00131 }
00132 
00133 // helper sort class
00134 struct LLSortRecentSpeakers
00135 {
00136         bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const;
00137 };
00138 
00139 bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const
00140 {
00141         // Sort first on status
00142         if (lhs->mStatus != rhs->mStatus) 
00143         {
00144                 return (lhs->mStatus < rhs->mStatus);
00145         }
00146 
00147         // and then on last speaking time
00148         if(lhs->mLastSpokeTime != rhs->mLastSpokeTime)
00149         {
00150                 return (lhs->mLastSpokeTime > rhs->mLastSpokeTime);
00151         }
00152         
00153         // and finally (only if those are both equal), on name.
00154         return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 );
00155 }
00156 
00157 //
00158 // LLFloaterActiveSpeakers
00159 //
00160 
00161 LLFloaterActiveSpeakers::LLFloaterActiveSpeakers(const LLSD& seed) : mPanel(NULL)
00162 {
00163         mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, NULL);
00164         // do not automatically open singleton floaters (as result of getInstance())
00165         BOOL no_open = FALSE;
00166         LLUICtrlFactory::getInstance()->buildFloater(this, "floater_active_speakers.xml", &getFactoryMap(), no_open);   
00167         //RN: for now, we poll voice client every frame to get voice amplitude feedback
00168         //gVoiceClient->addObserver(this);
00169         mPanel->refreshSpeakers();
00170 }
00171 
00172 LLFloaterActiveSpeakers::~LLFloaterActiveSpeakers()
00173 {
00174 }
00175 
00176 void LLFloaterActiveSpeakers::onOpen()
00177 {
00178         gSavedSettings.setBOOL("ShowActiveSpeakers", TRUE);
00179 }
00180 
00181 void LLFloaterActiveSpeakers::onClose(bool app_quitting)
00182 {
00183         if (!app_quitting)
00184         {
00185                 gSavedSettings.setBOOL("ShowActiveSpeakers", FALSE);
00186         }
00187         setVisible(FALSE);
00188 }
00189 
00190 void LLFloaterActiveSpeakers::draw()
00191 {
00192         // update state every frame to get live amplitude feedback
00193         mPanel->refreshSpeakers();
00194         LLFloater::draw();
00195 }
00196 
00197 BOOL LLFloaterActiveSpeakers::postBuild()
00198 {
00199         mPanel = getChild<LLPanelActiveSpeakers>("active_speakers_panel");
00200         return TRUE;
00201 }
00202 
00203 void LLFloaterActiveSpeakers::onChange()
00204 {
00205         //refresh();
00206 }
00207 
00208 //static
00209 void* LLFloaterActiveSpeakers::createSpeakersPanel(void* data)
00210 {
00211         // don't show text only speakers
00212         return new LLPanelActiveSpeakers(LLActiveSpeakerMgr::getInstance(), FALSE);
00213 }
00214 
00215 //
00216 // LLPanelActiveSpeakers::SpeakerMuteListener
00217 //
00218 bool LLPanelActiveSpeakers::SpeakerMuteListener::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
00219 {
00220         LLPointer<LLSpeaker> speakerp = (LLSpeaker*)event->getSource();
00221         if (speakerp.isNull()) return false;
00222 
00223         // update UI on confirmation of moderator mutes
00224         if (event->getValue().asString() == "voice")
00225         {
00226                 mPanel->childSetValue("moderator_allow_voice", !speakerp->mModeratorMutedVoice);
00227         }
00228         if (event->getValue().asString() == "text")
00229         {
00230                 mPanel->childSetValue("moderator_allow_text", !speakerp->mModeratorMutedText);
00231         }
00232         return true;
00233 }
00234 
00235 
00236 //
00237 // LLPanelActiveSpeakers::SpeakerAddListener
00238 //
00239 bool LLPanelActiveSpeakers::SpeakerAddListener::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
00240 {
00241         mPanel->addSpeaker(event->getValue().asUUID());
00242         return true;
00243 }
00244 
00245 
00246 //
00247 // LLPanelActiveSpeakers::SpeakerRemoveListener
00248 //
00249 bool LLPanelActiveSpeakers::SpeakerRemoveListener::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
00250 {
00251         mPanel->removeSpeaker(event->getValue().asUUID());
00252         return true;
00253 }
00254 
00255 //
00256 // LLPanelActiveSpeakers::SpeakerClearListener
00257 //
00258 bool LLPanelActiveSpeakers::SpeakerClearListener::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
00259 {
00260         mPanel->mSpeakerList->clearRows();
00261         return true;
00262 }
00263 
00264 
00265 //
00266 // LLPanelActiveSpeakers
00267 //
00268 LLPanelActiveSpeakers::LLPanelActiveSpeakers(LLSpeakerMgr* data_source, BOOL show_text_chatters) : 
00269         mSpeakerList(NULL),
00270         mMuteVoiceCtrl(NULL),
00271         mMuteTextCtrl(NULL),
00272         mNameText(NULL),
00273         mProfileBtn(NULL),
00274         mShowTextChatters(show_text_chatters),
00275         mSpeakerMgr(data_source)
00276 {
00277         setMouseOpaque(FALSE);
00278         mSpeakerMuteListener = new SpeakerMuteListener(this);
00279         mSpeakerAddListener = new SpeakerAddListener(this);
00280         mSpeakerRemoveListener = new SpeakerRemoveListener(this);
00281         mSpeakerClearListener = new SpeakerClearListener(this);
00282 
00283         mSpeakerMgr->addListener(mSpeakerAddListener, "add");
00284         mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove");
00285         mSpeakerMgr->addListener(mSpeakerClearListener, "clear");
00286 }
00287 
00288 BOOL LLPanelActiveSpeakers::postBuild()
00289 {
00290         std::string sort_column = gSavedSettings.getString(LLString("FloaterActiveSpeakersSortColumn"));
00291         BOOL sort_ascending     = gSavedSettings.getBOOL(  LLString("FloaterActiveSpeakersSortAscending"));
00292 
00293         mSpeakerList = getChild<LLScrollListCtrl>("speakers_list");
00294         mSpeakerList->sortByColumn(sort_column, sort_ascending);
00295         mSpeakerList->setDoubleClickCallback(onDoubleClickSpeaker);
00296         mSpeakerList->setCommitOnSelectionChange(TRUE);
00297         mSpeakerList->setCommitCallback(onSelectSpeaker);
00298         mSpeakerList->setSortChangedCallback(onSortChanged);
00299         mSpeakerList->setCallbackUserData(this);
00300 
00301         mMuteTextCtrl = getChild<LLUICtrl>("mute_text_btn");
00302         childSetCommitCallback("mute_text_btn", onClickMuteTextCommit, this);
00303 
00304         mMuteVoiceCtrl = getChild<LLUICtrl>("mute_btn");
00305         childSetCommitCallback("mute_btn", onClickMuteVoiceCommit, this);
00306         childSetAction("mute_btn", onClickMuteVoice, this);
00307 
00308         childSetCommitCallback("speaker_volume", onVolumeChange, this);
00309 
00310         mNameText = getChild<LLTextBox>("resident_name");
00311         
00312         mProfileBtn = getChild<LLButton>("profile_btn");
00313         childSetAction("profile_btn", onClickProfile, this);
00314 
00315         childSetCommitCallback("moderator_allow_voice", onModeratorMuteVoice, this);
00316         childSetCommitCallback("moderator_allow_text", onModeratorMuteText, this);
00317         childSetCommitCallback("moderation_mode", onChangeModerationMode, this);
00318 
00319         // update speaker UI
00320         handleSpeakerSelect();
00321 
00322         return TRUE;
00323 }
00324 
00325 void LLPanelActiveSpeakers::addSpeaker(const LLUUID& speaker_id)
00326 {
00327         if (mSpeakerList->getItemIndex(speaker_id) >= 0)
00328         {
00329                 // already have this speaker
00330                 return;
00331         }
00332 
00333         LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id);
00334         if (speakerp)
00335         {
00336                 // since we are forced to sort by text, encode sort order as string
00337                 LLString speaking_order_sort_string = llformat("%010d", speakerp->mSortIndex);
00338 
00339                 LLSD row;
00340                 row["id"] = speaker_id;
00341 
00342                 LLSD& columns = row["columns"];
00343 
00344                 columns[0]["column"] = "icon_speaking_status";
00345                 columns[0]["type"] = "icon";
00346                 columns[0]["value"] = "icn_active-speakers-dot-lvl0.tga";
00347 
00348                 LLString speaker_name;
00349                 if (speakerp->mDisplayName.empty())
00350                 {
00351                         speaker_name = LLCacheName::getDefaultName();
00352                 }
00353                 else
00354                 {
00355                         speaker_name = speakerp->mDisplayName;
00356                 }
00357                 columns[1]["column"] = "speaker_name";
00358                 columns[1]["type"] = "text";
00359                 columns[1]["value"] = speaker_name;
00360 
00361                 columns[2]["column"] = "speaking_status";
00362                 columns[2]["type"] = "text";
00363                 
00364                 // print speaking ordinal in a text-sorting friendly manner
00365                 columns[2]["value"] = speaking_order_sort_string;
00366 
00367                 mSpeakerList->addElement(row);
00368         }
00369 }
00370 
00371 void LLPanelActiveSpeakers::removeSpeaker(const LLUUID& speaker_id)
00372 {
00373         mSpeakerList->deleteSingleItem(mSpeakerList->getItemIndex(speaker_id));
00374 }
00375 
00376 void LLPanelActiveSpeakers::handleSpeakerSelect()
00377 {
00378         LLUUID speaker_id = mSpeakerList->getValue().asUUID();
00379         LLPointer<LLSpeaker> selected_speakerp = mSpeakerMgr->findSpeaker(speaker_id);
00380 
00381         if (selected_speakerp.notNull())
00382         {
00383                 // since setting these values is delayed by a round trip to the Vivox servers
00384                 // update them only when selecting a new speaker or
00385                 // asynchronously when an update arrives
00386                 childSetValue("moderator_allow_voice", selected_speakerp ? !selected_speakerp->mModeratorMutedVoice : TRUE);
00387                 childSetValue("moderator_allow_text", selected_speakerp ? !selected_speakerp->mModeratorMutedText : TRUE);
00388 
00389                 mSpeakerMuteListener->clearDispatchers();
00390                 selected_speakerp->addListener(mSpeakerMuteListener);
00391         }
00392 }
00393 
00394 void LLPanelActiveSpeakers::refreshSpeakers()
00395 {
00396         // store off current selection and scroll state to preserve across list rebuilds
00397         LLUUID selected_id = mSpeakerList->getSelectedValue().asUUID();
00398         S32 scroll_pos = mSpeakerList->getScrollInterface()->getScrollPos();
00399 
00400         mSpeakerMgr->update();
00401 
00402         const LLString icon_image_0 = "icn_active-speakers-dot-lvl0.tga";
00403         const LLString icon_image_1 = "icn_active-speakers-dot-lvl1.tga";
00404         const LLString icon_image_2 = "icn_active-speakers-dot-lvl2.tga";
00405 
00406         std::vector<LLScrollListItem*> items = mSpeakerList->getAllData();
00407 
00408         LLString mute_icon_image = "mute_icon.tga";
00409 
00410         LLSpeakerMgr::speaker_list_t speaker_list;
00411         mSpeakerMgr->getSpeakerList(&speaker_list, mShowTextChatters);
00412         for (std::vector<LLScrollListItem*>::iterator item_it = items.begin();
00413                 item_it != items.end();
00414                 ++item_it)
00415         {
00416                 LLScrollListItem* itemp = (*item_it);
00417                 LLUUID speaker_id = itemp->getUUID();
00418 
00419                 LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id);
00420                 if (!speakerp)
00421                 {
00422                         continue;
00423                 }
00424 
00425                 // since we are forced to sort by text, encode sort order as string
00426                 LLString speaking_order_sort_string = llformat("%010d", speakerp->mSortIndex);
00427 
00428                 LLScrollListCell* icon_cell = itemp->getColumn(0);
00429                 if (icon_cell)
00430                 {
00431 
00432                         LLString icon_image_id;
00433 
00434                         S32 icon_image_idx = llmin(2, llfloor((speakerp->mSpeechVolume / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f));
00435                         switch(icon_image_idx)
00436                         {
00437                         case 0:
00438                                 icon_image_id = icon_image_0;
00439                                 break;
00440                         case 1:
00441                                 icon_image_id = icon_image_1;
00442                                 break;
00443                         case 2:
00444                                 icon_image_id = icon_image_2;
00445                                 break;
00446                         }
00447 
00448                         LLColor4 icon_color;
00449                         if (speakerp->mStatus == LLSpeaker::STATUS_MUTED)
00450                         {
00451                                 icon_cell->setValue(mute_icon_image);
00452                                 if(speakerp->mModeratorMutedVoice)
00453                                 {
00454                                         icon_color.setVec(0.5f, 0.5f, 0.5f, 1.f);
00455                                 }
00456                                 else
00457                                 {
00458                                         icon_color.setVec(1.f, 71.f / 255.f, 71.f / 255.f, 1.f);
00459                                 }
00460                         }
00461                         else
00462                         {
00463                                 icon_cell->setValue(icon_image_id);
00464                                 icon_color = speakerp->mDotColor;
00465 
00466                                 if (speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE) // if voice is disabled for this speaker
00467                                 {
00468                                         // non voice speakers have hidden icons, render as transparent
00469                                         icon_color.setVec(0.f, 0.f, 0.f, 0.f);
00470                                 }
00471                         }
00472 
00473                         icon_cell->setColor(icon_color);
00474 
00475                         if (speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE && speakerp->mStatus != LLSpeaker::STATUS_MUTED) // if voice is disabled for this speaker
00476                         {
00477                                 // non voice speakers have hidden icons, render as transparent
00478                                 icon_cell->setColor(LLColor4::transparent);
00479                         }
00480                 }
00481 
00482                 // update name column
00483                 LLScrollListCell* name_cell = itemp->getColumn(1);
00484                 if (name_cell)
00485                 {
00486                         //FIXME: remove hard coding of font colors
00487                         if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL)      
00488                         {
00489                                 // draw inactive speakers in gray
00490                                 name_cell->setColor(LLColor4::grey4);
00491                         }
00492                         else
00493                         {
00494                                 name_cell->setColor(LLColor4::black);
00495                         }
00496 
00497                         LLString speaker_name;
00498                         if (speakerp->mDisplayName.empty())
00499                         {
00500                                 speaker_name = LLCacheName::getDefaultName();
00501                         }
00502                         else
00503                         {
00504                                 speaker_name = speakerp->mDisplayName;
00505                         }
00506 
00507                         if (speakerp->mIsModerator)
00508                         {
00509                                 speaker_name += LLString(" ") + getString("moderator_label");
00510                         }
00511                         
00512                         name_cell->setValue(speaker_name);
00513                         ((LLScrollListText*)name_cell)->setFontStyle(speakerp->mIsModerator ? LLFontGL::BOLD : LLFontGL::NORMAL);
00514                 }
00515 
00516                 // update speaking order column
00517                 LLScrollListCell* speaking_status_cell = itemp->getColumn(2);
00518                 if (speaking_status_cell)
00519                 {
00520                         // print speaking ordinal in a text-sorting friendly manner
00521                         speaking_status_cell->setValue(speaking_order_sort_string);
00522                 }
00523         }
00524         
00525         // we potentially modified the sort order by touching the list items
00526         mSpeakerList->setSorted(FALSE);
00527 
00528         LLPointer<LLSpeaker> selected_speakerp = mSpeakerMgr->findSpeaker(selected_id);
00529         // update UI for selected participant
00530         if (mMuteVoiceCtrl)
00531         {
00532                 mMuteVoiceCtrl->setValue(LLMuteList::getInstance()->isMuted(selected_id, LLMute::flagVoiceChat));
00533                 mMuteVoiceCtrl->setEnabled(LLVoiceClient::voiceEnabled()
00534                                                                         && gVoiceClient->getVoiceEnabled(selected_id)
00535                                                                         && selected_id.notNull() 
00536                                                                         && selected_id != gAgent.getID() 
00537                                                                         && (selected_speakerp.notNull() && selected_speakerp->mType == LLSpeaker::SPEAKER_AGENT));
00538         }
00539         if (mMuteTextCtrl)
00540         {
00541                 mMuteTextCtrl->setValue(LLMuteList::getInstance()->isMuted(selected_id, LLMute::flagTextChat));
00542                 mMuteTextCtrl->setEnabled(selected_id.notNull() 
00543                                                                 && selected_id != gAgent.getID() 
00544                                                                 && selected_speakerp.notNull() 
00545                                                                 && !LLMuteList::getInstance()->isLinden(selected_speakerp->mDisplayName));
00546         }
00547         childSetValue("speaker_volume", gVoiceClient->getUserVolume(selected_id));
00548         childSetEnabled("speaker_volume", LLVoiceClient::voiceEnabled()
00549                                         && gVoiceClient->getVoiceEnabled(selected_id)
00550                                         && selected_id.notNull() 
00551                                         && selected_id != gAgent.getID() 
00552                                         && (selected_speakerp.notNull() && selected_speakerp->mType == LLSpeaker::SPEAKER_AGENT));
00553 
00554         childSetEnabled(
00555                 "moderator_controls_label",
00556                 selected_id.notNull());
00557 
00558         childSetEnabled(
00559                 "moderator_allow_voice", 
00560                 selected_id.notNull() 
00561                 && mSpeakerMgr->isVoiceActive()
00562                 && gVoiceClient->getVoiceEnabled(selected_id));
00563 
00564         childSetEnabled(
00565                 "moderator_allow_text", 
00566                 selected_id.notNull());
00567 
00568         if (mProfileBtn)
00569         {
00570                 mProfileBtn->setEnabled(selected_id.notNull());
00571         }
00572 
00573         // show selected user name in large font
00574         if (mNameText)
00575         {
00576                 if (selected_speakerp)
00577                 {
00578                         mNameText->setValue(selected_speakerp->mDisplayName);
00579                 }
00580                 else
00581                 {
00582                         mNameText->setValue(LLString::null);
00583                 }
00584         }
00585 
00586         //update moderator capabilities
00587         LLPointer<LLSpeaker> self_speakerp = mSpeakerMgr->findSpeaker(gAgent.getID());
00588         if(self_speakerp)
00589         {
00590                 childSetVisible("moderation_mode_panel", self_speakerp->mIsModerator && mSpeakerMgr->isVoiceActive());
00591                 childSetVisible("moderator_controls", self_speakerp->mIsModerator);
00592         }
00593 
00594         // keep scroll value stable
00595         mSpeakerList->getScrollInterface()->setScrollPos(scroll_pos);
00596 }
00597 
00598 void LLPanelActiveSpeakers::setSpeaker(const LLUUID& id, const LLString& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
00599 {
00600         mSpeakerMgr->setSpeaker(id, name, status, type);
00601 }
00602 
00603 void LLPanelActiveSpeakers::setVoiceModerationCtrlMode(
00604         const BOOL& moderated_voice)
00605 {
00606         LLUICtrl* voice_moderation_ctrl = getChild<LLUICtrl>("moderation_mode");
00607 
00608         if ( voice_moderation_ctrl )
00609         {
00610                 std::string value;
00611 
00612                 value = moderated_voice ? "moderated" : "unmoderated";
00613                 voice_moderation_ctrl->setValue(value);
00614         }
00615 }
00616 
00617 //static
00618 void LLPanelActiveSpeakers::onClickMuteTextCommit(LLUICtrl* ctrl, void* user_data)
00619 {
00620         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00621         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00622         BOOL is_muted = LLMuteList::getInstance()->isMuted(speaker_id, LLMute::flagTextChat);
00623         std::string name;
00624 
00625         //fill in name using voice client's copy of name cache
00626         LLPointer<LLSpeaker> speakerp = panelp->mSpeakerMgr->findSpeaker(speaker_id);
00627         if (speakerp.isNull())
00628         {
00629                 return;
00630         }
00631         
00632         name = speakerp->mDisplayName;
00633 
00634         LLMute mute(speaker_id, name, speakerp->mType == LLSpeaker::SPEAKER_AGENT ? LLMute::AGENT : LLMute::OBJECT);
00635 
00636         if (!is_muted)
00637         {
00638                 LLMuteList::getInstance()->add(mute, LLMute::flagTextChat);
00639         }
00640         else
00641         {
00642                 LLMuteList::getInstance()->remove(mute, LLMute::flagTextChat);
00643         }
00644 }
00645 
00646 //static
00647 void LLPanelActiveSpeakers::onClickMuteVoice(void* user_data)
00648 {
00649         onClickMuteVoiceCommit(NULL, user_data);
00650 }
00651 
00652 //static
00653 void LLPanelActiveSpeakers::onClickMuteVoiceCommit(LLUICtrl* ctrl, void* user_data)
00654 {
00655         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00656         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00657         BOOL is_muted = LLMuteList::getInstance()->isMuted(speaker_id, LLMute::flagVoiceChat);
00658         std::string name;
00659 
00660         LLPointer<LLSpeaker> speakerp = panelp->mSpeakerMgr->findSpeaker(speaker_id);
00661         if (speakerp.isNull())
00662         {
00663                 return;
00664         }
00665 
00666         name = speakerp->mDisplayName;
00667 
00668         // muting voice means we're dealing with an agent
00669         LLMute mute(speaker_id, name, LLMute::AGENT);
00670 
00671         if (!is_muted)
00672         {
00673                 LLMuteList::getInstance()->add(mute, LLMute::flagVoiceChat);
00674         }
00675         else
00676         {
00677                 LLMuteList::getInstance()->remove(mute, LLMute::flagVoiceChat);
00678         }
00679 }
00680 
00681 
00682 //static
00683 void LLPanelActiveSpeakers::onVolumeChange(LLUICtrl* source, void* user_data)
00684 {
00685         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00686         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00687 
00688         F32 new_volume = (F32)panelp->childGetValue("speaker_volume").asReal();
00689         gVoiceClient->setUserVolume(speaker_id, new_volume); 
00690 
00691         // store this volume setting for future sessions
00692         LLMuteList::getInstance()->setSavedResidentVolume(speaker_id, new_volume);
00693 }
00694 
00695 //static 
00696 void LLPanelActiveSpeakers::onClickProfile(void* user_data)
00697 {
00698         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00699         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00700 
00701         LLFloaterAvatarInfo::showFromDirectory(speaker_id);
00702 }
00703 
00704 //static
00705 void LLPanelActiveSpeakers::onDoubleClickSpeaker(void* user_data)
00706 {
00707         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00708         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00709 
00710         LLPointer<LLSpeaker> speakerp = panelp->mSpeakerMgr->findSpeaker(speaker_id);
00711 
00712         if (speaker_id != gAgent.getID() && speakerp.notNull())
00713         {
00714                 gIMMgr->addSession(speakerp->mDisplayName, IM_NOTHING_SPECIAL, speaker_id);
00715         }
00716 }
00717 
00718 //static
00719 void LLPanelActiveSpeakers::onSelectSpeaker(LLUICtrl* source, void* user_data)
00720 {
00721         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00722         panelp->handleSpeakerSelect();
00723 }
00724 
00725 
00726 //static
00727 void LLPanelActiveSpeakers::onSortChanged(void* user_data)
00728 {
00729         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00730         std::string sort_column = panelp->mSpeakerList->getSortColumnName();
00731         BOOL sort_ascending = panelp->mSpeakerList->getSortAscending();
00732         gSavedSettings.setString(LLString("FloaterActiveSpeakersSortColumn"), sort_column);
00733         gSavedSettings.setBOOL(  LLString("FloaterActiveSpeakersSortAscending"), sort_ascending);
00734 }
00735 
00736 
00737 //static 
00738 void LLPanelActiveSpeakers::onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data)
00739 {
00740         LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data;
00741         LLUICtrl* speakers_list = self->getChild<LLUICtrl>("speakers_list");
00742         if (!speakers_list || !gAgent.getRegion()) return;
00743 
00744         std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
00745         LLSD data;
00746         data["method"] = "mute update";
00747         data["session-id"] = self->mSpeakerMgr->getSessionID();
00748         data["params"] = LLSD::emptyMap();
00749         data["params"]["agent_id"] = speakers_list->getValue();
00750         data["params"]["mutes"] = LLSD::emptyMap();
00751         // ctrl value represents ability to type, so invert
00752         data["params"]["mutes"]["voice"] = !ctrl->getValue();
00753 
00754         class MuteVoiceResponder : public LLHTTPClient::Responder
00755         {
00756         public:
00757                 MuteVoiceResponder(const LLUUID& session_id)
00758                 {
00759                         mSessionID = session_id;
00760                 }
00761 
00762                 virtual void error(U32 status, const std::string& reason)
00763                 {
00764                         llwarns << status << ": " << reason << llendl;
00765 
00766                         if ( gIMMgr )
00767                         {
00768                                 //403 == you're not a mod
00769                                 //should be disabled if you're not a moderator
00770                                 LLFloaterIMPanel* floaterp;
00771 
00772                                 floaterp = gIMMgr->findFloaterBySession(mSessionID);
00773 
00774                                 if ( floaterp )
00775                                 {
00776                                         if ( 403 == status )
00777                                         {
00778                                                 floaterp->showSessionEventError(
00779                                                         "mute",
00780                                                         "not_a_moderator");
00781                                         }
00782                                         else
00783                                         {
00784                                                 floaterp->showSessionEventError(
00785                                                         "mute",
00786                                                         "generic");
00787                                         }
00788                                 }
00789                         }
00790                 }
00791 
00792         private:
00793                 LLUUID mSessionID;
00794         };
00795 
00796         LLHTTPClient::post(
00797                 url,
00798                 data,
00799                 new MuteVoiceResponder(self->mSpeakerMgr->getSessionID()));
00800 }
00801 
00802 //static 
00803 void LLPanelActiveSpeakers::onModeratorMuteText(LLUICtrl* ctrl, void* user_data)
00804 {
00805         LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data;
00806         LLUICtrl* speakers_list = self->getChild<LLUICtrl>("speakers_list");
00807         if (!speakers_list || !gAgent.getRegion()) return;
00808 
00809         std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
00810         LLSD data;
00811         data["method"] = "mute update";
00812         data["session-id"] = self->mSpeakerMgr->getSessionID();
00813         data["params"] = LLSD::emptyMap();
00814         data["params"]["agent_id"] = speakers_list->getValue();
00815         data["params"]["mutes"] = LLSD::emptyMap();
00816         // ctrl value represents ability to type, so invert
00817         data["params"]["mutes"]["text"] = !ctrl->getValue();
00818 
00819         class MuteTextResponder : public LLHTTPClient::Responder
00820         {
00821         public:
00822                 MuteTextResponder(const LLUUID& session_id)
00823                 {
00824                         mSessionID = session_id;
00825                 }
00826 
00827                 virtual void error(U32 status, const std::string& reason)
00828                 {
00829                         llwarns << status << ": " << reason << llendl;
00830 
00831                         if ( gIMMgr )
00832                         {
00833                                 //403 == you're not a mod
00834                                 //should be disabled if you're not a moderator
00835                                 LLFloaterIMPanel* floaterp;
00836 
00837                                 floaterp = gIMMgr->findFloaterBySession(mSessionID);
00838 
00839                                 if ( floaterp )
00840                                 {
00841                                         if ( 403 == status )
00842                                         {
00843                                                 floaterp->showSessionEventError(
00844                                                         "mute",
00845                                                         "not_a_moderator");
00846                                         }
00847                                         else
00848                                         {
00849                                                 floaterp->showSessionEventError(
00850                                                         "mute",
00851                                                         "generic");
00852                                         }
00853                                 }
00854                         }
00855                 }
00856 
00857         private:
00858                 LLUUID mSessionID;
00859         };
00860 
00861         LLHTTPClient::post(
00862                 url,
00863                 data,
00864                 new MuteTextResponder(self->mSpeakerMgr->getSessionID()));
00865 }
00866 
00867 //static
00868 void LLPanelActiveSpeakers::onChangeModerationMode(LLUICtrl* ctrl, void* user_data)
00869 {
00870         LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data;
00871         if (!gAgent.getRegion()) return;
00872 
00873         std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
00874         LLSD data;
00875         data["method"] = "session update";
00876         data["session-id"] = self->mSpeakerMgr->getSessionID();
00877         data["params"] = LLSD::emptyMap();
00878         data["params"]["moderated_mode"] = LLSD::emptyMap();
00879         if (ctrl->getValue().asString() == "unmoderated")
00880         {
00881                 data["params"]["moderated_mode"]["voice"] = false;
00882         }
00883         else if (ctrl->getValue().asString() == "moderated")
00884         {
00885                 data["params"]["moderated_mode"]["voice"] = true;
00886         }
00887 
00888         struct ModerationModeResponder : public LLHTTPClient::Responder
00889         {
00890                 virtual void error(U32 status, const std::string& reason)
00891                 {
00892                         llwarns << status << ": " << reason << llendl;
00893                 }
00894         };
00895 
00896         LLHTTPClient::post(url, data, new ModerationModeResponder());
00897 }
00898 
00899 //
00900 // LLSpeakerMgr
00901 //
00902 
00903 LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : 
00904         mVoiceChannel(channelp)
00905 {
00906 }
00907 
00908 LLSpeakerMgr::~LLSpeakerMgr()
00909 {
00910 }
00911 
00912 LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const LLString& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
00913 {
00914         if (id.isNull()) return NULL;
00915 
00916         LLPointer<LLSpeaker> speakerp;
00917         if (mSpeakers.find(id) == mSpeakers.end())
00918         {
00919                 speakerp = new LLSpeaker(id, name, type);
00920                 speakerp->mStatus = status;
00921                 mSpeakers.insert(std::make_pair(speakerp->mID, speakerp));
00922                 mSpeakersSorted.push_back(speakerp);
00923                 fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add");
00924         }
00925         else
00926         {
00927                 speakerp = findSpeaker(id);
00928                 if (speakerp.notNull())
00929                 {
00930                         // keep highest priority status (lowest value) instead of overriding current value
00931                         speakerp->mStatus = llmin(speakerp->mStatus, status);
00932                         speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
00933                         // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id
00934                         // we need to override speakers that we think are objects when we find out they are really
00935                         // residents
00936                         if (type == LLSpeaker::SPEAKER_AGENT)
00937                         {
00938                                 speakerp->mType = LLSpeaker::SPEAKER_AGENT;
00939                                 speakerp->lookupName();
00940                         }
00941                 }
00942         }
00943 
00944         return speakerp;
00945 }
00946 
00947 void LLSpeakerMgr::update()
00948 {
00949         if (!gVoiceClient)
00950         {
00951                 return;
00952         }
00953         
00954         LLColor4 speaking_color = gSavedSettings.getColor4("SpeakingColor");
00955         LLColor4 overdriven_color = gSavedSettings.getColor4("OverdrivenColor");
00956 
00957         updateSpeakerList();
00958 
00959         // update status of all current speakers
00960         BOOL voice_channel_active = (!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
00961         for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)
00962         {
00963                 LLUUID speaker_id = speaker_it->first;
00964                 LLSpeaker* speakerp = speaker_it->second;
00965                 
00966                 speaker_map_t::iterator  cur_speaker_it = speaker_it++;
00967 
00968                 if (voice_channel_active && gVoiceClient->getVoiceEnabled(speaker_id))
00969                 {
00970                         speakerp->mSpeechVolume = gVoiceClient->getCurrentPower(speaker_id);
00971                         BOOL moderator_muted_voice = gVoiceClient->getIsModeratorMuted(speaker_id);
00972                         if (moderator_muted_voice != speakerp->mModeratorMutedVoice)
00973                         {
00974                                 speakerp->mModeratorMutedVoice = moderator_muted_voice;
00975                                 speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp));
00976                         }
00977 
00978                         if (gVoiceClient->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice)
00979                         {
00980                                 speakerp->mStatus = LLSpeaker::STATUS_MUTED;
00981                         }
00982                         else if (gVoiceClient->getIsSpeaking(speaker_id))
00983                         {
00984                                 // reset inactivity expiration
00985                                 if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING)
00986                                 {
00987                                         speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
00988                                         speakerp->mHasSpoken = TRUE;
00989                                 }
00990                                 speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
00991                                 // interpolate between active color and full speaking color based on power of speech output
00992                                 speakerp->mDotColor = speaking_color;
00993                                 if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL)
00994                                 {
00995                                         speakerp->mDotColor = overdriven_color;
00996                                 }
00997                         }
00998                         else
00999                         {
01000                                 speakerp->mSpeechVolume = 0.f;
01001                                 speakerp->mDotColor = ACTIVE_COLOR;
01002 
01003                                 if (speakerp->mHasSpoken)
01004                                 {
01005                                         // have spoken once, not currently speaking
01006                                         speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN;
01007                                 }
01008                                 else
01009                                 {
01010                                         // default state for being in voice channel
01011                                         speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE;
01012                                 }
01013                         }
01014                 }
01015                 // speaker no longer registered in voice channel, demote to text only
01016                 else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL)
01017                 {
01018                         speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY;
01019                         speakerp->mSpeechVolume = 0.f;
01020                         speakerp->mDotColor = ACTIVE_COLOR;
01021                 }
01022         }
01023 
01024         // sort by status then time last spoken
01025         std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers());
01026 
01027         // for recent speakers who are not currently speaking, show "recent" color dot for most recent
01028         // fading to "active" color
01029 
01030         S32 recent_speaker_count = 0;
01031         S32 sort_index = 0;
01032         speaker_list_t::iterator sorted_speaker_it;
01033         for(sorted_speaker_it = mSpeakersSorted.begin(); 
01034                 sorted_speaker_it != mSpeakersSorted.end(); )
01035         {
01036                 LLPointer<LLSpeaker> speakerp = *sorted_speaker_it;
01037                 
01038                 // color code recent speakers who are not currently speaking
01039                 if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN)
01040                 {
01041                         speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f));
01042                         recent_speaker_count++;
01043                 }
01044 
01045                 // stuff sort ordinal into speaker so the ui can sort by this value
01046                 speakerp->mSortIndex = sort_index++;
01047 
01048                 // remove speakers that have been gone too long
01049                 if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL && speakerp->mActivityTimer.hasExpired())
01050                 {
01051                         fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "remove");
01052 
01053                         mSpeakers.erase(speakerp->mID);
01054                         sorted_speaker_it = mSpeakersSorted.erase(sorted_speaker_it);
01055                 }
01056                 else
01057                 {
01058                         ++sorted_speaker_it;
01059                 }
01060         }
01061 }
01062 
01063 void LLSpeakerMgr::updateSpeakerList()
01064 {
01065         // are we bound to the currently active voice channel?
01066         if ((!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()))
01067         {
01068                 LLVoiceClient::participantMap* participants = gVoiceClient->getParticipantList();
01069                 LLVoiceClient::participantMap::iterator participant_it;
01070 
01071                 // add new participants to our list of known speakers
01072                 for (participant_it = participants->begin(); participant_it != participants->end(); ++participant_it)
01073                 {
01074                         LLVoiceClient::participantState* participantp = participant_it->second;
01075                         setSpeaker(participantp->mAvatarID, "", LLSpeaker::STATUS_VOICE_ACTIVE);
01076                 }
01077         }
01078 }
01079 
01080 const LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id)
01081 {
01082         speaker_map_t::iterator found_it = mSpeakers.find(speaker_id);
01083         if (found_it == mSpeakers.end())
01084         {
01085                 return NULL;
01086         }
01087         return found_it->second;
01088 }
01089 
01090 void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text)
01091 {
01092         speaker_list->clear();
01093         for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
01094         {
01095                 LLPointer<LLSpeaker> speakerp = speaker_it->second;
01096                 // what about text only muted or inactive?
01097                 if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY)
01098                 {
01099                         speaker_list->push_back(speakerp);
01100                 }
01101         }
01102 }
01103 
01104 const LLUUID LLSpeakerMgr::getSessionID() 
01105 { 
01106         return mVoiceChannel->getSessionID(); 
01107 }
01108 
01109 
01110 void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing)
01111 {
01112         LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
01113         if (speakerp.notNull())
01114         {
01115                 speakerp->mTyping = typing;
01116         }
01117 }
01118 
01119 // speaker has chatted via either text or voice
01120 void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
01121 {
01122         LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
01123         if (speakerp.notNull())
01124         {
01125                 speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
01126                 speakerp->mHasSpoken = TRUE;
01127         }
01128 }
01129 
01130 BOOL LLSpeakerMgr::isVoiceActive()
01131 {
01132         // mVoiceChannel = NULL means current voice channel, whatever it is
01133         return LLVoiceClient::voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();
01134 }
01135 
01136 
01137 //
01138 // LLIMSpeakerMgr
01139 //
01140 LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel)
01141 {
01142 }
01143 
01144 void LLIMSpeakerMgr::updateSpeakerList()
01145 {
01146         // don't do normal updates which are pulled from voice channel
01147         // rely on user list reported by sim
01148         return;
01149 }
01150 
01151 void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers)
01152 {
01153         if ( !speakers.isMap() ) return;
01154 
01155         if ( speakers.has("agent_info") && speakers["agent_info"].isMap() )
01156         {
01157                 LLSD::map_const_iterator speaker_it;
01158                 for(speaker_it = speakers["agent_info"].beginMap();
01159                         speaker_it != speakers["agent_info"].endMap();
01160                         ++speaker_it)
01161                 {
01162                         LLUUID agent_id(speaker_it->first);
01163 
01164                         LLPointer<LLSpeaker> speakerp = setSpeaker(
01165                                 agent_id,
01166                                 "",
01167                                 LLSpeaker::STATUS_TEXT_ONLY);
01168 
01169                         if ( speaker_it->second.isMap() )
01170                         {
01171                                 speakerp->mIsModerator = speaker_it->second["is_moderator"];
01172                                 speakerp->mModeratorMutedText =
01173                                         speaker_it->second["mutes"]["text"];
01174                         }
01175                 }
01176         }
01177         else if ( speakers.has("agents" ) && speakers["agents"].isArray() )
01178         {
01179                 //older, more decprecated way.  Need here for
01180                 //using older version of servers
01181                 LLSD::array_const_iterator speaker_it;
01182                 for(speaker_it = speakers["agents"].beginArray();
01183                         speaker_it != speakers["agents"].endArray();
01184                         ++speaker_it)
01185                 {
01186                         const LLUUID agent_id = (*speaker_it).asUUID();
01187 
01188                         LLPointer<LLSpeaker> speakerp = setSpeaker(
01189                                 agent_id,
01190                                 "",
01191                                 LLSpeaker::STATUS_TEXT_ONLY);
01192                 }
01193         }
01194 }
01195 
01196 void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
01197 {
01198         if ( !update.isMap() ) return;
01199 
01200         if ( update.has("agent_updates") && update["agent_updates"].isMap() )
01201         {
01202                 LLSD::map_const_iterator update_it;
01203                 for(
01204                         update_it = update["agent_updates"].beginMap();
01205                         update_it != update["agent_updates"].endMap();
01206                         ++update_it)
01207                 {
01208                         LLUUID agent_id(update_it->first);
01209                         LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
01210 
01211                         LLSD agent_data = update_it->second;
01212 
01213                         if (agent_data.isMap() && agent_data.has("transition"))
01214                         {
01215                                 if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull())
01216                                 {
01217                                         speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
01218                                         speakerp->mDotColor = INACTIVE_COLOR;
01219                                         speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
01220                                 }
01221                                 else if (agent_data["transition"].asString() == "ENTER")
01222                                 {
01223                                         // add or update speaker
01224                                         speakerp = setSpeaker(agent_id);
01225                                 }
01226                                 else
01227                                 {
01228                                         llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl;
01229                                 }
01230                         }
01231 
01232                         if (speakerp.isNull()) continue;
01233 
01234                         // should have a valid speaker from this point on
01235                         if (agent_data.isMap() && agent_data.has("info"))
01236                         {
01237                                 LLSD agent_info = agent_data["info"];
01238 
01239                                 if (agent_info.has("is_moderator"))
01240                                 {
01241                                         speakerp->mIsModerator = agent_info["is_moderator"];
01242                                 }
01243 
01244                                 if (agent_info.has("mutes"))
01245                                 {
01246                                         speakerp->mModeratorMutedText = agent_info["mutes"]["text"];
01247                                 }
01248                         }
01249                 }
01250         }
01251         else if ( update.has("updates") && update["updates"].isMap() )
01252         {
01253                 LLSD::map_const_iterator update_it;
01254                 for (
01255                         update_it = update["updates"].beginMap();
01256                         update_it != update["updates"].endMap();
01257                         ++update_it)
01258                 {
01259                         LLUUID agent_id(update_it->first);
01260                         LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
01261 
01262                         std::string agent_transition = update_it->second.asString();
01263                         if (agent_transition == "LEAVE" && speakerp.notNull())
01264                         {
01265                                 speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
01266                                 speakerp->mDotColor = INACTIVE_COLOR;
01267                                 speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
01268                         }
01269                         else if ( agent_transition == "ENTER")
01270                         {
01271                                 // add or update speaker
01272                                 speakerp = setSpeaker(agent_id);
01273                         }
01274                         else
01275                         {
01276                                 llwarns << "bad membership list update "
01277                                                 << agent_transition << llendl;
01278                         }
01279                 }
01280         }
01281 }
01282 
01283 
01284 //
01285 // LLActiveSpeakerMgr
01286 //
01287 
01288 LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL)
01289 {
01290 }
01291 
01292 void LLActiveSpeakerMgr::updateSpeakerList()
01293 {
01294         // point to whatever the current voice channel is
01295         mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
01296 
01297         // always populate from active voice channel
01298         if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel)
01299         {
01300                 fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear");
01301                 mSpeakers.clear();
01302                 mSpeakersSorted.clear();
01303                 mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
01304         }
01305         LLSpeakerMgr::updateSpeakerList();
01306 
01307         // clean up text only speakers
01308         for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
01309         {
01310                 LLUUID speaker_id = speaker_it->first;
01311                 LLSpeaker* speakerp = speaker_it->second;
01312                 if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
01313                 {
01314                         // automatically flag text only speakers for removal
01315                         speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
01316                 }
01317         }
01318 
01319 }
01320 
01321 
01322 
01323 //
01324 // LLLocalSpeakerMgr
01325 //
01326 
01327 LLLocalSpeakerMgr::LLLocalSpeakerMgr() : LLSpeakerMgr(LLVoiceChannelProximal::getInstance())
01328 {
01329 }
01330 
01331 LLLocalSpeakerMgr::~LLLocalSpeakerMgr ()
01332 {
01333 }
01334 
01335 void LLLocalSpeakerMgr::updateSpeakerList()
01336 {
01337         // pull speakers from voice channel
01338         LLSpeakerMgr::updateSpeakerList();
01339 
01340         // add non-voice speakers in chat range
01341         std::vector< LLCharacter* >::iterator avatar_it;
01342         for(avatar_it = LLCharacter::sInstances.begin(); avatar_it != LLCharacter::sInstances.end(); ++avatar_it)
01343         {
01344                 LLVOAvatar* avatarp = (LLVOAvatar*)*avatar_it;
01345                 if (dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) <= CHAT_NORMAL_RADIUS)
01346                 {
01347                         setSpeaker(avatarp->getID());
01348                 }
01349         }
01350 
01351         // check if text only speakers have moved out of chat range
01352         for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
01353         {
01354                 LLUUID speaker_id = speaker_it->first;
01355                 LLSpeaker* speakerp = speaker_it->second;
01356                 if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
01357                 {
01358                         LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id);
01359                         if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS)
01360                         {
01361                                 speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
01362                                 speakerp->mDotColor = INACTIVE_COLOR;
01363                                 speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
01364                         }
01365                 }
01366         }
01367 }

Generated on Fri May 16 08:33:22 2008 for SecondLife by  doxygen 1.5.5