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 "llvieweruictrlfactory.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 
00049 const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers
00050 const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f);
00051 const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f);
00052 const F32 TYPING_ANIMATION_FPS = 2.5f;
00053 
00054 LLLocalSpeakerMgr*      gLocalSpeakerMgr = NULL;
00055 LLActiveSpeakerMgr*             gActiveChannelSpeakerMgr = NULL;
00056 
00057 LLSpeaker::speaker_map_t LLSpeaker::sSpeakers;
00058 
00059 LLSpeaker::LLSpeaker(const LLUUID& id, const LLString& name, const ESpeakerType type) : 
00060         mStatus(LLSpeaker::STATUS_TEXT_ONLY),
00061         mLastSpokeTime(0.f), 
00062         mSpeechVolume(0.f), 
00063         mHasSpoken(FALSE),
00064         mDotColor(LLColor4::white),
00065         mID(id),
00066         mTyping(FALSE),
00067         mSortIndex(0),
00068         mType(type)
00069 {
00070         mHandle.init();
00071         sSpeakers.insert(std::make_pair(mHandle, this));
00072         if (name.empty() && type == SPEAKER_AGENT)
00073         {
00074                 lookupName();
00075         }
00076         else
00077         {
00078                 mDisplayName = name;
00079         }
00080         mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
00081 }
00082 
00083 LLSpeaker::~LLSpeaker()
00084 {
00085         sSpeakers.erase(mHandle);
00086 }
00087 
00088 void LLSpeaker::lookupName()
00089 {
00090         gCacheName->getName(mID, onAvatarNameLookup, new LLViewHandle(mHandle));
00091 }
00092 
00093 //static 
00094 void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* user_data)
00095 {
00096         LLViewHandle speaker_handle = *(LLViewHandle*)user_data;
00097         delete (LLViewHandle*)user_data;
00098 
00099         speaker_map_t::iterator found_it = sSpeakers.find(speaker_handle);
00100         if (found_it != sSpeakers.end())
00101         {
00102                 LLSpeaker* speakerp = found_it->second;
00103                 if (speakerp)
00104                 {
00105                         speakerp->mDisplayName = llformat("%s %s", first, last);
00106                 }
00107         }
00108 }
00109 
00110 
00111 // helper sort class
00112 struct LLSortRecentSpeakers
00113 {
00114         bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const;
00115 };
00116 
00117 bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const
00118 {
00119         // Sort first on status
00120         if (lhs->mStatus != rhs->mStatus) 
00121         {
00122                 return (lhs->mStatus < rhs->mStatus);
00123         }
00124 
00125         // and then on last speaking time
00126         if(lhs->mLastSpokeTime != rhs->mLastSpokeTime)
00127         {
00128                 return (lhs->mLastSpokeTime > rhs->mLastSpokeTime);
00129         }
00130         
00131         // and finally (only if those are both equal), on name.
00132         return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 );
00133 }
00134 
00135 LLFloaterActiveSpeakers::LLFloaterActiveSpeakers(const LLSD& seed) : mPanel(NULL)
00136 {
00137         mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, NULL);
00138         // do not automatically open singleton floaters (as result of getInstance())
00139         BOOL no_open = FALSE;
00140         gUICtrlFactory->buildFloater(this, "floater_active_speakers.xml", &getFactoryMap(), no_open);   
00141         //RN: for now, we poll voice client every frame to get voice amplitude feedback
00142         //gVoiceClient->addObserver(this);
00143         mPanel->refreshSpeakers();
00144 }
00145 
00146 LLFloaterActiveSpeakers::~LLFloaterActiveSpeakers()
00147 {
00148 }
00149 
00150 void LLFloaterActiveSpeakers::onClose(bool app_quitting)
00151 {
00152         setVisible(FALSE);
00153 }
00154 
00155 void LLFloaterActiveSpeakers::draw()
00156 {
00157         // update state every frame to get live amplitude feedback
00158         mPanel->refreshSpeakers();
00159         LLFloater::draw();
00160 }
00161 
00162 BOOL LLFloaterActiveSpeakers::postBuild()
00163 {
00164         mPanel = (LLPanelActiveSpeakers*)LLUICtrlFactory::getPanelByName(this, "active_speakers_panel");
00165         return TRUE;
00166 }
00167 
00168 void LLFloaterActiveSpeakers::onChange()
00169 {
00170         //refresh();
00171 }
00172 
00173 //static
00174 void* LLFloaterActiveSpeakers::createSpeakersPanel(void* data)
00175 {
00176         // don't show text only speakers
00177         return new LLPanelActiveSpeakers(gActiveChannelSpeakerMgr, FALSE);
00178 }
00179 
00180 
00181 //
00182 // LLPanelActiveSpeakers
00183 //
00184 LLPanelActiveSpeakers::LLPanelActiveSpeakers(LLSpeakerMgr* data_source, BOOL show_text_chatters) : 
00185         mSpeakerList(NULL),
00186         mMuteVoiceCtrl(NULL),
00187         mMuteTextCtrl(NULL),
00188         mNameText(NULL),
00189         mProfileBtn(NULL),
00190         mShowTextChatters(show_text_chatters),
00191         mSpeakerMgr(data_source)
00192 {
00193         setMouseOpaque(FALSE);
00194 }
00195 
00196 LLPanelActiveSpeakers::~LLPanelActiveSpeakers()
00197 {
00198         
00199 }
00200 
00201 BOOL LLPanelActiveSpeakers::postBuild()
00202 {
00203         mSpeakerList = LLUICtrlFactory::getScrollListByName(this, "speakers_list");
00204 
00205         mMuteTextCtrl = (LLUICtrl*)getCtrlByNameAndType("mute_text_btn", WIDGET_TYPE_DONTCARE);
00206         childSetCommitCallback("mute_text_btn", onClickMuteTextCommit, this);
00207 
00208         mMuteVoiceCtrl = (LLUICtrl*)getCtrlByNameAndType("mute_btn", WIDGET_TYPE_DONTCARE);
00209         childSetCommitCallback("mute_btn", onClickMuteVoiceCommit, this);
00210         childSetAction("mute_btn", onClickMuteVoice, this);
00211 
00212         childSetCommitCallback("speaker_volume", onVolumeChange, this);
00213 
00214         mNameText = LLUICtrlFactory::getTextBoxByName(this, "resident_name");
00215         
00216         mProfileBtn = LLUICtrlFactory::getButtonByName(this, "profile_btn");
00217         childSetAction("profile_btn", onClickProfile, this);
00218         return TRUE;
00219 }
00220 
00221 void LLPanelActiveSpeakers::refreshSpeakers()
00222 {
00223         // store off current selection and scroll state to preserve across list rebuilds
00224         LLUUID selected_id = mSpeakerList->getSimpleSelectedValue().asUUID();
00225         S32 scroll_pos = mSpeakerList->getScrollInterface()->getScrollPos();
00226 
00227         BOOL sort_ascending = mSpeakerList->getSortAscending();
00228         LLString sort_column = mSpeakerList->getSortColumnName();
00229         // TODO: put this in xml
00230         // enforces default sort column of speaker status
00231         if (sort_column.empty())
00232         {
00233                 sort_column = "speaking_status";
00234         }
00235 
00236         mSpeakerMgr->update();
00237 
00238         // clear scrolling list widget of names
00239         mSpeakerList->clearRows();
00240 
00241         LLSpeakerMgr::speaker_list_t speaker_list;
00242         mSpeakerMgr->getSpeakerList(&speaker_list, mShowTextChatters);
00243         for (LLSpeakerMgr::speaker_list_t::const_iterator speaker_it = speaker_list.begin(); speaker_it != speaker_list.end(); ++speaker_it)
00244         {
00245                 LLUUID speaker_id = (*speaker_it)->mID;
00246                 LLPointer<LLSpeaker> speakerp = (*speaker_it);
00247 
00248                 // since we are forced to sort by text, encode sort order as string
00249                 LLString speaking_order_sort_string = llformat("%010d", speakerp->mSortIndex);
00250 
00251                 LLSD row;
00252                 row["id"] = speaker_id;
00253 
00254                 row["columns"][0]["column"] = "icon_speaking_status";
00255                 row["columns"][0]["type"] = "icon";
00256                 row["columns"][0]["color"] = speakerp->mDotColor.getValue();
00257                 LLString icon_image_id;
00258 
00259                 S32 icon_image_idx = llmin(2, llfloor((speakerp->mSpeechVolume / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f));
00260                 switch(icon_image_idx)
00261                 {
00262                 case 0:
00263                         icon_image_id = gViewerArt.getString("icn_active-speakers-dot-lvl0.tga");
00264                         break;
00265                 case 1:
00266                         icon_image_id = gViewerArt.getString("icn_active-speakers-dot-lvl1.tga");
00267                         break;
00268                 case 2:
00269                         icon_image_id = gViewerArt.getString("icn_active-speakers-dot-lvl2.tga");
00270                         break;
00271                 }
00272                 //if (speakerp->mTyping)
00273                 //{
00274                 //      S32 typing_anim_idx = llround(mIconAnimationTimer.getElapsedTimeF32() * TYPING_ANIMATION_FPS) % 3;
00275                 //      switch(typing_anim_idx)
00276                 //      {
00277                 //      case 0:
00278                 //              row["columns"][0]["overlay"] = LLUUID(gViewerArt.getString("icn_active-speakers-typing1.tga"));
00279                 //              break;
00280                 //      case 1:
00281                 //              row["columns"][0]["overlay"] = LLUUID(gViewerArt.getString("icn_active-speakers-typing2.tga"));
00282                 //              break;
00283                 //      case 2:
00284                 //              row["columns"][0]["overlay"] = LLUUID(gViewerArt.getString("icn_active-speakers-typing3.tga"));
00285                 //              break;
00286                 //      default:
00287                 //              break;
00288                 //      }
00289                 //}
00290 
00291                 row["columns"][0]["value"] = (speakerp->mStatus == LLSpeaker::STATUS_MUTED) ?
00292                         gViewerArt.getString("mute_icon.tga") : icon_image_id;
00293                 if (speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE && speakerp->mStatus != LLSpeaker::STATUS_MUTED) // if voice is disabled for this speaker
00294                 {
00295                         // non voice speakers have hidden icons, render as transparent
00296                         row["columns"][0]["color"] = LLColor4(0.f, 0.f, 0.f, 0.f).getValue();
00297                 }
00298                 row["columns"][1]["column"] = "speaker_name";
00299                 row["columns"][1]["type"] = "text";
00300                 if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL)      
00301                 {
00302                         // draw inactive speakers in gray
00303                         row["columns"][1]["color"] = LLColor4::grey4.getValue();
00304                 }
00305 
00306                 if (speakerp->mDisplayName.empty())
00307                 {
00308                         row["columns"][1]["value"] = LLCacheName::getDefaultName();
00309                 }
00310                 else
00311                 {
00312                         row["columns"][1]["value"] = speakerp->mDisplayName;
00313                 }
00314 
00315                 row["columns"][2]["column"] = "speaking_status";
00316                 row["columns"][2]["type"] = "text";
00317                 
00318                 // print speaking ordinal in a text-sorting friendly manner
00319                 row["columns"][2]["value"] = speaking_order_sort_string;
00320 
00321                 mSpeakerList->addElement(row);
00322         }
00323         
00324         //restore sort order, selection, etc
00325         mSpeakerList->sortByColumn(sort_column, sort_ascending);
00326         // make sure something is selected
00327         if (selected_id.isNull())
00328         {
00329                 mSpeakerList->selectFirstItem();
00330         }
00331         else
00332         {
00333                 mSpeakerList->selectByValue(selected_id);
00334         }
00335 
00336         LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(selected_id);
00337         
00338         if (gMuteListp)
00339         {
00340                 // update UI for selected participant
00341                 if (mMuteVoiceCtrl)
00342                 {
00343                         mMuteVoiceCtrl->setValue(gMuteListp->isMuted(selected_id, LLMute::flagVoiceChat));
00344                         mMuteVoiceCtrl->setEnabled(selected_id.notNull() 
00345                                                                                 && selected_id != gAgent.getID() 
00346                                                                                 && (speakerp.notNull() && speakerp->mType == LLSpeaker::SPEAKER_AGENT));
00347                 }
00348                 if (mMuteTextCtrl)
00349                 {
00350                         mMuteTextCtrl->setValue(gMuteListp->isMuted(selected_id, LLMute::flagTextChat));
00351                         mMuteTextCtrl->setEnabled(selected_id.notNull() && selected_id != gAgent.getID() && speakerp.notNull() && !gMuteListp->isLinden(speakerp->mDisplayName));
00352                 }
00353                 childSetValue("speaker_volume", gVoiceClient->getUserVolume(selected_id));
00354                 childSetEnabled("speaker_volume", selected_id.notNull() 
00355                                                 && selected_id != gAgent.getID() 
00356                                                 && (speakerp.notNull() && speakerp->mType == LLSpeaker::SPEAKER_AGENT));
00357                 if (mProfileBtn)
00358                 {
00359                         mProfileBtn->setEnabled(selected_id.notNull());
00360                 }
00361         }
00362 
00363         // show selected user name in large font
00364         if (mNameText)
00365         {
00366                 if (speakerp)
00367                 {
00368                         mNameText->setValue(speakerp->mDisplayName);
00369                 }
00370                 else
00371                 {
00372                         mNameText->setValue(LLString::null);
00373                 }
00374         }
00375 
00376         // keep scroll value stable
00377         mSpeakerList->getScrollInterface()->setScrollPos(scroll_pos);
00378 }
00379 
00380 void LLPanelActiveSpeakers::setSpeaker(const LLUUID& id, const LLString& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
00381 {
00382         mSpeakerMgr->setSpeaker(id, name, status, type);
00383 }
00384 
00385 
00386 //static
00387 void LLPanelActiveSpeakers::onClickMuteTextCommit(LLUICtrl* ctrl, void* user_data)
00388 {
00389         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00390         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00391         BOOL is_muted = gMuteListp->isMuted(speaker_id, LLMute::flagTextChat);
00392         std::string name;
00393 
00394         //fill in name using voice client's copy of name cache
00395         LLPointer<LLSpeaker> speakerp = panelp->mSpeakerMgr->findSpeaker(speaker_id);
00396         if (speakerp.isNull())
00397         {
00398                 return;
00399         }
00400         
00401         name = speakerp->mDisplayName;
00402 
00403         LLMute mute(speaker_id, name, speakerp->mType == LLSpeaker::SPEAKER_AGENT ? LLMute::AGENT : LLMute::OBJECT);
00404 
00405         if (!is_muted)
00406         {
00407                 gMuteListp->add(mute, LLMute::flagTextChat);
00408         }
00409         else
00410         {
00411                 gMuteListp->remove(mute, LLMute::flagTextChat);
00412         }
00413 }
00414 
00415 //static
00416 void LLPanelActiveSpeakers::onClickMuteVoice(void* user_data)
00417 {
00418         onClickMuteVoiceCommit(NULL, user_data);
00419 }
00420 
00421 //static
00422 void LLPanelActiveSpeakers::onClickMuteVoiceCommit(LLUICtrl* ctrl, void* user_data)
00423 {
00424         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00425         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00426         BOOL is_muted = gMuteListp->isMuted(speaker_id, LLMute::flagVoiceChat);
00427         std::string name;
00428 
00429         LLPointer<LLSpeaker> speakerp = panelp->mSpeakerMgr->findSpeaker(speaker_id);
00430         if (speakerp.isNull())
00431         {
00432                 return;
00433         }
00434 
00435         name = speakerp->mDisplayName;
00436 
00437         // muting voice means we're dealing with an agent
00438         LLMute mute(speaker_id, name, LLMute::AGENT);
00439 
00440         if (!is_muted)
00441         {
00442                 gMuteListp->add(mute, LLMute::flagVoiceChat);
00443         }
00444         else
00445         {
00446                 gMuteListp->remove(mute, LLMute::flagVoiceChat);
00447         }
00448 }
00449 
00450 
00451 //static
00452 void LLPanelActiveSpeakers::onVolumeChange(LLUICtrl* source, void* user_data)
00453 {
00454         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00455         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00456 
00457         gVoiceClient->setUserVolume(speaker_id, (F32)panelp->childGetValue("speaker_volume").asReal());
00458 }
00459 
00460 //static 
00461 void LLPanelActiveSpeakers::onClickProfile(void* user_data)
00462 {
00463         LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data;
00464         LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID();
00465 
00466         LLFloaterAvatarInfo::showFromDirectory(speaker_id);
00467 }
00468  
00469 //
00470 // LLSpeakerMgr
00471 //
00472 
00473 LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : 
00474         mVoiceChannel(channelp)
00475 {
00476 }
00477 
00478 LLSpeakerMgr::~LLSpeakerMgr()
00479 {
00480 }
00481 
00482 LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const LLString& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
00483 {
00484         if (id.isNull()) return NULL;
00485 
00486         LLPointer<LLSpeaker> speakerp;
00487         if (mSpeakers.find(id) == mSpeakers.end())
00488         {
00489                 speakerp = new LLSpeaker(id, name, type);
00490                 speakerp->mStatus = status;
00491                 mSpeakers.insert(std::make_pair(speakerp->mID, speakerp));
00492                 mSpeakersSorted.push_back(speakerp);
00493         }
00494         else
00495         {
00496                 speakerp = findSpeaker(id);
00497                 if (speakerp.notNull())
00498                 {
00499                         // keep highest priority status (lowest value) instead of overriding current value
00500                         speakerp->mStatus = llmin(speakerp->mStatus, status);
00501                         speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
00502                         // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id
00503                         // we need to override speakers that we think are objects when we find out they are really
00504                         // residents
00505                         if (type == LLSpeaker::SPEAKER_AGENT)
00506                         {
00507                                 speakerp->mType = LLSpeaker::SPEAKER_AGENT;
00508                                 speakerp->lookupName();
00509                         }
00510                 }
00511         }
00512 
00513         return speakerp;
00514 }
00515 
00516 void LLSpeakerMgr::update()
00517 {
00518         if (!gVoiceClient)
00519         {
00520                 return;
00521         }
00522         
00523         LLColor4 speaking_color = gSavedSettings.getColor4("SpeakingColor");
00524         LLColor4 overdriven_color = gSavedSettings.getColor4("OverdrivenColor");
00525 
00526         updateSpeakerList();
00527 
00528         // update status of all current speakers
00529         BOOL voice_channel_active = (!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
00530         for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)
00531         {
00532                 LLUUID speaker_id = speaker_it->first;
00533                 LLSpeaker* speakerp = speaker_it->second;
00534                 
00535                 speaker_map_t::iterator  cur_speaker_it = speaker_it++;
00536 
00537                 if (voice_channel_active && gVoiceClient->getVoiceEnabled(speaker_id))
00538                 {
00539                         speakerp->mSpeechVolume = gVoiceClient->getCurrentPower(speaker_id);
00540 
00541                         if (gVoiceClient->getOnMuteList(speaker_id))
00542                         {
00543                                 speakerp->mStatus = LLSpeaker::STATUS_MUTED;
00544                                 speakerp->mDotColor = LLColor4::white;
00545                         }
00546                         else if (gVoiceClient->getIsSpeaking(speaker_id))
00547                         {
00548                                 // reset inactivity expiration
00549                                 if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING)
00550                                 {
00551                                         speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
00552                                         speakerp->mHasSpoken = TRUE;
00553                                 }
00554                                 speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
00555                                 // interpolate between active color and full speaking color based on power of speech output
00556                                 speakerp->mDotColor = speaking_color;
00557                                 if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL)
00558                                 {
00559                                         speakerp->mDotColor = overdriven_color;
00560                                 }
00561                         }
00562                         else
00563                         {
00564                                 speakerp->mSpeechVolume = 0.f;
00565                                 speakerp->mDotColor = ACTIVE_COLOR;
00566 
00567                                 if (speakerp->mHasSpoken)
00568                                 {
00569                                         // have spoken once, not currently speaking
00570                                         speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN;
00571                                 }
00572                                 else
00573                                 {
00574                                         // default state for being in voice channel
00575                                         speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE;
00576                                 }
00577                         }
00578                 }
00579                 // speaker no longer registered in voice channel, demote to text only
00580                 else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL)
00581                 {
00582                         speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY;
00583                         speakerp->mSpeechVolume = 0.f;
00584                         speakerp->mDotColor = ACTIVE_COLOR;
00585                 }
00586         }
00587 
00588         // sort by status then time last spoken
00589         std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers());
00590 
00591         // for recent speakers who are not currently speaking, show "recent" color dot for most recent
00592         // fading to "active" color
00593 
00594         S32 recent_speaker_count = 0;
00595         S32 sort_index = 0;
00596         speaker_list_t::iterator sorted_speaker_it;
00597         for(sorted_speaker_it = mSpeakersSorted.begin(); 
00598                 sorted_speaker_it != mSpeakersSorted.end(); )
00599         {
00600                 LLPointer<LLSpeaker> speakerp = *sorted_speaker_it;
00601                 
00602                 // color code recent speakers who are not currently speaking
00603                 if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN)
00604                 {
00605                         speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f));
00606                         recent_speaker_count++;
00607                 }
00608 
00609                 // stuff sort ordinal into speaker so the ui can sort by this value
00610                 speakerp->mSortIndex = sort_index++;
00611 
00612                 // remove speakers that have been gone too long
00613                 if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL && speakerp->mActivityTimer.hasExpired())
00614                 {
00615                         mSpeakers.erase(speakerp->mID);
00616                         sorted_speaker_it = mSpeakersSorted.erase(sorted_speaker_it);
00617                 }
00618                 else
00619                 {
00620                         ++sorted_speaker_it;
00621                 }
00622         }
00623 }
00624 
00625 void LLSpeakerMgr::updateSpeakerList()
00626 {
00627         // are we bound to the currently active voice channel?
00628         if ((!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()))
00629         {
00630                 LLVoiceClient::participantMap* participants = gVoiceClient->getParticipantList();
00631                 LLVoiceClient::participantMap::iterator participant_it;
00632 
00633                 // add new participants to our list of known speakers
00634                 for (participant_it = participants->begin(); participant_it != participants->end(); ++participant_it)
00635                 {
00636                         LLVoiceClient::participantState* participantp = participant_it->second;
00637                         setSpeaker(participantp->mAvatarID, "", LLSpeaker::STATUS_VOICE_ACTIVE);
00638                 }
00639         }
00640 }
00641 
00642 const LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id)
00643 {
00644         speaker_map_t::iterator found_it = mSpeakers.find(speaker_id);
00645         if (found_it == mSpeakers.end())
00646         {
00647                 return NULL;
00648         }
00649         return found_it->second;
00650 }
00651 
00652 void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text)
00653 {
00654         speaker_list->clear();
00655         for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
00656         {
00657                 LLPointer<LLSpeaker> speakerp = speaker_it->second;
00658                 // what about text only muted or inactive?
00659                 if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY)
00660                 {
00661                         speaker_list->push_back(speakerp);
00662                 }
00663         }
00664 }
00665 
00666 void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing)
00667 {
00668         LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
00669         if (speakerp.notNull())
00670         {
00671                 speakerp->mTyping = typing;
00672         }
00673 }
00674 
00675 // speaker has chatted via either text or voice
00676 void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
00677 {
00678         LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
00679         if (speakerp.notNull())
00680         {
00681                 speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
00682                 speakerp->mHasSpoken = TRUE;
00683         }
00684 }
00685 
00686 BOOL LLSpeakerMgr::isVoiceActive()
00687 {
00688         // mVoiceChannel = NULL means current voice channel, whatever it is
00689         return LLVoiceClient::voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();
00690 }
00691 
00692 
00693 //
00694 // LLIMSpeakerMgr
00695 //
00696 LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel)
00697 {
00698 }
00699 
00700 void LLIMSpeakerMgr::updateSpeakerList()
00701 {
00702         // don't do normal updates which are pulled from voice channel
00703         // rely on user list reported by sim
00704         return;
00705 }
00706 
00707 void LLIMSpeakerMgr::processSpeakerList(LLSD list)
00708 {
00709         for(LLSD::array_iterator list_it = list.beginArray();
00710                 list_it != list.endArray();
00711                 ++list_it)
00712         {
00713                 LLUUID agent_id(list_it->asUUID());
00714 
00715                 setSpeaker(agent_id, "", LLSpeaker::STATUS_TEXT_ONLY);
00716         }
00717 }
00718 
00719 void LLIMSpeakerMgr::processSpeakerMap(LLSD map)
00720 {
00721         for(LLSD::map_iterator map_it = map.beginMap();
00722                 map_it != map.endMap();
00723                 ++map_it)
00724         {
00725                 // add as new speaker
00726                 setSpeaker(LLUUID(map_it->first));
00727         }
00728 }
00729 
00730 
00731 
00732 void LLIMSpeakerMgr::processSpeakerListUpdate(LLSD update)
00733 {
00734         for(LLSD::map_iterator update_it = update.beginMap();
00735                 update_it != update.endMap();
00736                 ++update_it)
00737         {
00738                 LLUUID agent_id(update_it->first);
00739                 
00740                 if (update_it->second.asString() == "LEAVE")
00741                 {
00742                         LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
00743                         if (speakerp)
00744                         {
00745                                 speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
00746                                 speakerp->mDotColor = INACTIVE_COLOR;
00747                                 speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
00748                         }
00749                 }
00750                 else if (update_it->second.asString() == "ENTER")
00751                 {
00752                         // add or update speaker
00753                         setSpeaker(agent_id);
00754                 }
00755                 else
00756                 {
00757                         llwarns << "LLIMSpeakerMgr::processSpeakerListUpdate() : bad membership list update " << ll_print_sd(update_it->second) << llendl;
00758                 }
00759         }
00760 }
00761 
00762 
00763 //
00764 // LLActiveSpeakerMgr
00765 //
00766 
00767 LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL)
00768 {
00769 }
00770 
00771 void LLActiveSpeakerMgr::updateSpeakerList()
00772 {
00773         // point to whatever the current voice channel is
00774         mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
00775 
00776         // always populate from active voice channel
00777         if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel)
00778         {
00779                 mSpeakers.clear();
00780                 mSpeakersSorted.clear();
00781                 mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
00782         }
00783         LLSpeakerMgr::updateSpeakerList();
00784 }
00785 
00786 
00787 
00788 //
00789 // LLLocalSpeakerMgr
00790 //
00791 
00792 LLLocalSpeakerMgr::LLLocalSpeakerMgr() : LLSpeakerMgr(LLVoiceChannelProximal::getInstance())
00793 {
00794 }
00795 
00796 LLLocalSpeakerMgr::~LLLocalSpeakerMgr ()
00797 {
00798 }
00799 
00800 void LLLocalSpeakerMgr::updateSpeakerList()
00801 {
00802         // pull speakers from voice channel
00803         LLSpeakerMgr::updateSpeakerList();
00804 
00805         // add non-voice speakers in chat range
00806         std::vector< LLCharacter* >::iterator avatar_it;
00807         for(avatar_it = LLCharacter::sInstances.begin(); avatar_it != LLCharacter::sInstances.end(); ++avatar_it)
00808         {
00809                 LLVOAvatar* avatarp = (LLVOAvatar*)*avatar_it;
00810                 if (dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) <= CHAT_NORMAL_RADIUS)
00811                 {
00812                         setSpeaker(avatarp->getID());
00813                 }
00814         }
00815 
00816         // check if text only speakers have moved out of chat range
00817         for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
00818         {
00819                 LLUUID speaker_id = speaker_it->first;
00820                 LLSpeaker* speakerp = speaker_it->second;
00821                 if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
00822                 {
00823                         LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id);
00824                         if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS)
00825                         {
00826                                 speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
00827                                 speakerp->mDotColor = INACTIVE_COLOR;
00828                                 speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);
00829                         }
00830                 }
00831         }
00832 }

Generated on Thu Jul 1 06:08:31 2010 for Second Life Viewer by  doxygen 1.4.7