Merge remote-tracking branch 'lirusaito/master'
This commit is contained in:
@@ -924,9 +924,7 @@ P(meshLODResponder);
|
||||
P(meshPhysicsShapeResponder);
|
||||
P(meshSkinInfoResponder);
|
||||
P(mimeDiscoveryResponder);
|
||||
P(moderationModeResponder);
|
||||
P(muteTextResponder);
|
||||
P(muteVoiceResponder);
|
||||
P(moderationResponder);
|
||||
P(navMeshRebakeResponder);
|
||||
P(navMeshResponder);
|
||||
P(navMeshStatusResponder);
|
||||
@@ -954,9 +952,9 @@ P(viewerChatterBoxInvitationAcceptResponder);
|
||||
P(viewerMediaOpenIDResponder);
|
||||
P(viewerMediaWebProfileResponder);
|
||||
P(viewerStatsResponder);
|
||||
P(viewerVoiceAccountProvisionResponder);
|
||||
P(vivoxVoiceAccountProvisionResponder);
|
||||
P(vivoxVoiceClientCapResponder);
|
||||
P(voiceCallCapResponder);
|
||||
P(voiceClientCapResponder);
|
||||
P(webProfileResponders);
|
||||
P(wholeModelFeeResponder);
|
||||
P(wholeModelUploadResponder);
|
||||
|
||||
@@ -261,7 +261,6 @@ set(viewer_SOURCE_FILES
|
||||
llfloatertos.cpp
|
||||
llfloaterurldisplay.cpp
|
||||
llfloaterurlentry.cpp
|
||||
llfloatervoicedevicesettings.cpp
|
||||
llfloaterwater.cpp
|
||||
llfloaterwindlight.cpp
|
||||
llfloaterworldmap.cpp
|
||||
@@ -379,9 +378,11 @@ set(viewer_SOURCE_FILES
|
||||
llpanelplace.cpp
|
||||
llpanelprofile.cpp
|
||||
llpanelskins.cpp
|
||||
llpanelvoicedevicesettings.cpp
|
||||
llpanelvolume.cpp
|
||||
llpanelweb.cpp
|
||||
llparcelselection.cpp
|
||||
llparticipantlist.cpp
|
||||
llpatchvertexarray.cpp
|
||||
llpathfindingcharacter.cpp
|
||||
llpathfindingcharacterlist.cpp
|
||||
@@ -417,6 +418,7 @@ set(viewer_SOURCE_FILES
|
||||
llselectmgr.cpp
|
||||
llsky.cpp
|
||||
llspatialpartition.cpp
|
||||
llspeakers.cpp
|
||||
llsprite.cpp
|
||||
llstartup.cpp
|
||||
llstatusbar.cpp
|
||||
@@ -520,9 +522,11 @@ set(viewer_SOURCE_FILES
|
||||
llvoclouds.cpp
|
||||
llvograss.cpp
|
||||
llvoground.cpp
|
||||
llvoicechannel.cpp
|
||||
llvoiceclient.cpp
|
||||
llvoiceremotectrl.cpp
|
||||
llvoicevisualizer.cpp
|
||||
llvoicevivox.cpp
|
||||
llvoinventorylistener.cpp
|
||||
llvopartgroup.cpp
|
||||
llvosky.cpp
|
||||
@@ -762,7 +766,6 @@ set(viewer_HEADER_FILES
|
||||
llfloatertos.h
|
||||
llfloaterurldisplay.h
|
||||
llfloaterurlentry.h
|
||||
llfloatervoicedevicesettings.h
|
||||
llfloaterwater.h
|
||||
llfloaterwindlight.h
|
||||
llfloaterworldmap.h
|
||||
@@ -880,9 +883,11 @@ set(viewer_HEADER_FILES
|
||||
llpanelplace.h
|
||||
llpanelprofile.h
|
||||
llpanelskins.h
|
||||
llpanelvoicedevicesettings.h
|
||||
llpanelvolume.h
|
||||
llpanelweb.h
|
||||
llparcelselection.h
|
||||
llparticipantlist.h
|
||||
llpatchvertexarray.h
|
||||
llpathfindingcharacter.h
|
||||
llpathfindingcharacterlist.h
|
||||
@@ -920,6 +925,7 @@ set(viewer_HEADER_FILES
|
||||
llsimplestat.h
|
||||
llsky.h
|
||||
llspatialpartition.h
|
||||
llspeakers.h
|
||||
llsprite.h
|
||||
llstartup.h
|
||||
llstatusbar.h
|
||||
@@ -1026,9 +1032,11 @@ set(viewer_HEADER_FILES
|
||||
llvoclouds.h
|
||||
llvograss.h
|
||||
llvoground.h
|
||||
llvoicechannel.h
|
||||
llvoiceclient.h
|
||||
llvoiceremotectrl.h
|
||||
llvoicevisualizer.h
|
||||
llvoicevivox.h
|
||||
llvoinventorylistener.h
|
||||
llvopartgroup.h
|
||||
llvosky.h
|
||||
|
||||
@@ -14096,6 +14096,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>ShowVoiceVisualizersInCalls</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enables in-world voice visualizers, voice gestures and lip-sync while in group or P2P calls.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>ShowVolumeSettingsPopup</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -15387,6 +15398,28 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SpeakerParticipantDefaultOrder</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Order for displaying speakers in voice controls. 0 = alphabetical. 1 = recent.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>SpeakerParticipantRemoveDelay</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Timeout to remove participants who is not in channel before removed from list of active speakers (text/voice chat)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>10.0</real>
|
||||
</map>
|
||||
<key>UseNewWalkRun</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -15617,6 +15650,50 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>VoiceCallsRejectGroup</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Silently reject all incoming group voice calls.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>VoiceDisableMic</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Completely disable the ability to open the mic.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>VoiceEffectExpiryWarningTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>How much notice to give of Voice Morph subscriptions expiry, in seconds.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>259200</integer>
|
||||
</map>
|
||||
<key>VoiceMorphingEnabled</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not to enable Voice Morphs and show the UI.</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>AutoDisengageMic</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -15628,6 +15705,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>ShowDeviceSettings</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Show device settings</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>VoiceEarLocation</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -15738,6 +15826,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<string>Default</string>
|
||||
</map>
|
||||
<key>VoiceLogFile</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Log file to use when launching the voice daemon</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string></string>
|
||||
</map>
|
||||
<key>VoiceOutputAudioDevice</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -15771,6 +15870,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>VoiceServerType</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>The type of voice server to connect to.</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>vivox</string>
|
||||
</map>
|
||||
<key>WLSkyDetail</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
@@ -573,6 +573,17 @@
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>VoiceEffectDefault</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Selected Voice Morph</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>00000000-0000-0000-0000-000000000000</string>
|
||||
</map>
|
||||
<key>LogFileNamewithDate</key>
|
||||
<map>
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "llsdutil.h"
|
||||
#include "llsky.h"
|
||||
#include "llsmoothstep.h"
|
||||
#include "llspeakers.h"
|
||||
#include "llstartup.h"
|
||||
#include "llstatusbar.h"
|
||||
#include "lltool.h"
|
||||
@@ -76,6 +77,7 @@
|
||||
#include "llviewerstats.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llvoavatarself.h"
|
||||
#include "llvoiceclient.h"
|
||||
#include "llworld.h"
|
||||
#include "llworldmap.h"
|
||||
#include "llworldmapmessage.h"
|
||||
@@ -84,11 +86,9 @@
|
||||
#include "llurldispatcher.h"
|
||||
#include "llimview.h" //For gIMMgr
|
||||
//Floaters
|
||||
#include "llfloateractivespeakers.h"
|
||||
#include "llfloateravatarinfo.h"
|
||||
#include "llfloaterchat.h"
|
||||
#include "llfloaterdirectory.h"
|
||||
#include "llfloatergroupinfo.h"
|
||||
#include "llfloatergroups.h"
|
||||
#include "llfloaterland.h"
|
||||
#include "llfloatermap.h"
|
||||
@@ -260,6 +260,56 @@ void LLAgent::parcelChangedCallback()
|
||||
gAgent.mCanEditParcel = can_edit;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAgent::isActionAllowed(const LLSD& sdname)
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
const std::string& param = sdname.asString();
|
||||
|
||||
if (param == "speak")
|
||||
{
|
||||
if ( gAgent.isVoiceConnected() &&
|
||||
LLViewerParcelMgr::getInstance()->allowAgentVoice() &&
|
||||
! LLVoiceClient::getInstance()->inTuningMode() )
|
||||
{
|
||||
retval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLAgent::pressMicrophone(const LLSD& name)
|
||||
{
|
||||
//LLFirstUse::speak(false);
|
||||
|
||||
LLVoiceClient::getInstance()->inputUserControlState(true);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLAgent::releaseMicrophone(const LLSD& name)
|
||||
{
|
||||
LLVoiceClient::getInstance()->inputUserControlState(false);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLAgent::toggleMicrophone(const LLSD& name)
|
||||
{
|
||||
LLVoiceClient::getInstance()->toggleUserPTTState();
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAgent::isMicrophoneOn(const LLSD& sdname)
|
||||
{
|
||||
return LLVoiceClient::getInstance()->getUserPTTState();
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// Enabled this definition to compile a 'hacked' viewer that
|
||||
// locally believes the end user has godlike powers.
|
||||
@@ -3909,7 +3959,7 @@ bool LLAgent::teleportCore(bool is_local)
|
||||
|
||||
// MBW -- Let the voice client know a teleport has begun so it can leave the existing channel.
|
||||
// This was breaking the case of teleporting within a single sim. Backing it out for now.
|
||||
// gVoiceClient->leaveChannel();
|
||||
// LLVoiceClient::getInstance()->leaveChannel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -313,6 +313,22 @@ public:
|
||||
static bool enableFlying();
|
||||
BOOL canFly(); // Does this parcel allow you to fly?
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Voice
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
bool isVoiceConnected() const { return mVoiceConnected; }
|
||||
void setVoiceConnected(const bool b) { mVoiceConnected = b; }
|
||||
|
||||
static void pressMicrophone(const LLSD& name);
|
||||
static void releaseMicrophone(const LLSD& name);
|
||||
static void toggleMicrophone(const LLSD& name);
|
||||
static bool isMicrophoneOn(const LLSD& sdname);
|
||||
static bool isActionAllowed(const LLSD& sdname);
|
||||
|
||||
private:
|
||||
bool mVoiceConnected;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Chat
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
#include "llfirstuse.h"
|
||||
#include "llrender.h"
|
||||
#include "llvector4a.h"
|
||||
#include "llimpanel.h" // For LLVoiceClient and LLVoiceChannel
|
||||
#include "llvoicechannel.h"
|
||||
#include "llvoavatarself.h"
|
||||
#include "llprogressview.h"
|
||||
#include "llvocache.h"
|
||||
@@ -1095,7 +1095,7 @@ bool LLAppViewer::mainLoop()
|
||||
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
|
||||
|
||||
LLVoiceChannel::initClass();
|
||||
LLVoiceClient::init(gServicePump);
|
||||
LLVoiceClient::getInstance()->init(gServicePump);
|
||||
|
||||
LLTimer frameTimer,idleTimer,periodicRenderingTimer;
|
||||
LLTimer debugTime;
|
||||
@@ -1452,7 +1452,7 @@ bool LLAppViewer::cleanup()
|
||||
// to ensure shutdown order
|
||||
LLMortician::setZealous(TRUE);
|
||||
|
||||
LLVoiceClient::terminate();
|
||||
LLVoiceClient::getInstance()->terminate();
|
||||
|
||||
disconnectViewer();
|
||||
|
||||
@@ -4270,8 +4270,10 @@ void LLAppViewer::sendLogoutRequest()
|
||||
gLogoutMaxTime = LOGOUT_REQUEST_TIME;
|
||||
mLogoutRequestSent = TRUE;
|
||||
|
||||
if(gVoiceClient)
|
||||
gVoiceClient->leaveChannel();
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceClient::getInstance()->leaveChannel();
|
||||
}
|
||||
|
||||
//Set internal status variables and marker files
|
||||
gLogoutInProgress = TRUE;
|
||||
|
||||
@@ -299,7 +299,7 @@ bool LLAvatarActions::isCalling(const LLUUID &id)
|
||||
//static
|
||||
bool LLAvatarActions::canCall()
|
||||
{
|
||||
return LLVoiceClient::getInstance()->voiceEnabled() /*&& LLVoiceClient::getInstance()->isVoiceWorking()*/;
|
||||
return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -510,6 +510,26 @@ void LLAvatarActions::toggleBlock(const LLUUID& id)
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLAvatarActions::toggleMuteVoice(const LLUUID& id)
|
||||
{
|
||||
std::string name;
|
||||
gCacheName->getFullName(id, name); // needed for mute
|
||||
|
||||
LLMuteList* mute_list = LLMuteList::getInstance();
|
||||
bool is_muted = mute_list->isMuted(id, LLMute::flagVoiceChat);
|
||||
|
||||
LLMute mute(id, name, LLMute::AGENT);
|
||||
if (!is_muted)
|
||||
{
|
||||
mute_list->add(mute, LLMute::flagVoiceChat);
|
||||
}
|
||||
else
|
||||
{
|
||||
mute_list->remove(mute, LLMute::flagVoiceChat);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAvatarActions::canOfferTeleport(const LLUUID& id)
|
||||
{
|
||||
@@ -724,6 +744,12 @@ bool LLAvatarActions::isBlocked(const LLUUID& id)
|
||||
return LLMuteList::getInstance()->isMuted(id);
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAvatarActions::isVoiceMuted(const LLUUID& id)
|
||||
{
|
||||
return LLMuteList::getInstance()->isMuted(id, LLMute::flagVoiceChat);
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLAvatarActions::canBlock(const LLUUID& id)
|
||||
{
|
||||
|
||||
@@ -104,6 +104,11 @@ public:
|
||||
*/
|
||||
static void toggleBlock(const LLUUID& id);
|
||||
|
||||
/**
|
||||
* Block/unblock the avatar voice.
|
||||
*/
|
||||
static void toggleMuteVoice(const LLUUID& id);
|
||||
|
||||
/**
|
||||
* Return true if avatar with "id" is a friend
|
||||
*/
|
||||
@@ -114,6 +119,11 @@ public:
|
||||
*/
|
||||
static bool isBlocked(const LLUUID& id);
|
||||
|
||||
/**
|
||||
* @return true if the avatar voice is blocked
|
||||
*/
|
||||
static bool isVoiceMuted(const LLUUID& id);
|
||||
|
||||
/**
|
||||
* @return true if you can block the avatar
|
||||
*/
|
||||
@@ -185,4 +195,3 @@ public:
|
||||
};
|
||||
|
||||
#endif // LL_LLAVATARACTIONS_H
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,9 @@
|
||||
* @brief Management interface for muting and controlling volume of residents currently speaking
|
||||
*
|
||||
* $LicenseInfo:firstyear=2005&license=viewergpl$
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (c) 2005-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
@@ -33,155 +32,10 @@
|
||||
#ifndef LL_LLFLOATERACTIVESPEAKERS_H
|
||||
#define LL_LLFLOATERACTIVESPEAKERS_H
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llfloater.h"
|
||||
#include "llmemory.h"
|
||||
#include "llvoiceclient.h"
|
||||
#include "llframetimer.h"
|
||||
#include "llevent.h"
|
||||
|
||||
#include <list>
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLScrollListCtrl;
|
||||
class LLButton;
|
||||
class LLPanelActiveSpeakers;
|
||||
class LLSpeakerMgr;
|
||||
class LLVoiceChannel;
|
||||
class LLSlider;
|
||||
class LLTextBox;
|
||||
class LLCheckBoxCtrl;
|
||||
|
||||
|
||||
// data for a given participant in a voice channel
|
||||
class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable
|
||||
{
|
||||
public:
|
||||
typedef enum e_speaker_type
|
||||
{
|
||||
SPEAKER_AGENT,
|
||||
SPEAKER_OBJECT,
|
||||
SPEAKER_EXTERNAL // Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group)
|
||||
} ESpeakerType;
|
||||
|
||||
typedef enum e_speaker_status
|
||||
{
|
||||
STATUS_SPEAKING,
|
||||
STATUS_HAS_SPOKEN,
|
||||
STATUS_VOICE_ACTIVE,
|
||||
STATUS_TEXT_ONLY,
|
||||
STATUS_NOT_IN_CHANNEL,
|
||||
STATUS_MUTED
|
||||
} ESpeakerStatus;
|
||||
|
||||
|
||||
LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT);
|
||||
~LLSpeaker() {};
|
||||
void lookupName();
|
||||
void onNameCache(const LLAvatarName& avatar_name);
|
||||
|
||||
ESpeakerStatus mStatus; // current activity status in speech group
|
||||
F32 mLastSpokeTime; // timestamp when this speaker last spoke
|
||||
F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?)
|
||||
std::string mDisplayName; // cache user name for this speaker
|
||||
LLFrameTimer mActivityTimer; // time out speakers when they are not part of current voice channel
|
||||
BOOL mHasSpoken; // has this speaker said anything this session?
|
||||
LLColor4 mDotColor;
|
||||
LLUUID mID;
|
||||
BOOL mTyping;
|
||||
S32 mSortIndex;
|
||||
ESpeakerType mType;
|
||||
BOOL mIsModerator;
|
||||
BOOL mModeratorMutedVoice;
|
||||
BOOL mModeratorMutedText;
|
||||
std::string mLegacyName;
|
||||
bool mNameRequested;
|
||||
};
|
||||
|
||||
class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent
|
||||
{
|
||||
public:
|
||||
LLSpeakerTextModerationEvent(LLSpeaker* source);
|
||||
/*virtual*/ LLSD getValue();
|
||||
};
|
||||
|
||||
class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent
|
||||
{
|
||||
public:
|
||||
LLSpeakerVoiceModerationEvent(LLSpeaker* source);
|
||||
/*virtual*/ LLSD getValue();
|
||||
};
|
||||
|
||||
class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent
|
||||
{
|
||||
public:
|
||||
LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id);
|
||||
/*virtual*/ LLSD getValue();
|
||||
|
||||
private:
|
||||
const LLUUID& mSpeakerID;
|
||||
};
|
||||
|
||||
class LLSpeakerMgr : public LLOldEvents::LLObservable
|
||||
{
|
||||
public:
|
||||
LLSpeakerMgr(LLVoiceChannel* channelp);
|
||||
virtual ~LLSpeakerMgr();
|
||||
|
||||
const LLPointer<LLSpeaker> findSpeaker(const LLUUID& avatar_id);
|
||||
void update(BOOL resort_ok);
|
||||
void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing);
|
||||
void speakerChatted(const LLUUID& speaker_id);
|
||||
LLPointer<LLSpeaker> setSpeaker(const LLUUID& id,
|
||||
const std::string& name = LLStringUtil::null,
|
||||
LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY,
|
||||
LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT);
|
||||
|
||||
BOOL isVoiceActive();
|
||||
|
||||
typedef std::vector<LLPointer<LLSpeaker> > speaker_list_t;
|
||||
void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text);
|
||||
const LLUUID getSessionID();
|
||||
|
||||
protected:
|
||||
virtual void updateSpeakerList();
|
||||
|
||||
typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t;
|
||||
speaker_map_t mSpeakers;
|
||||
|
||||
speaker_list_t mSpeakersSorted;
|
||||
LLFrameTimer mSpeechTimer;
|
||||
LLVoiceChannel* mVoiceChannel;
|
||||
};
|
||||
|
||||
class LLIMSpeakerMgr : public LLSpeakerMgr
|
||||
{
|
||||
public:
|
||||
LLIMSpeakerMgr(LLVoiceChannel* channel);
|
||||
|
||||
void updateSpeakers(const LLSD& update);
|
||||
void setSpeakers(const LLSD& speakers);
|
||||
protected:
|
||||
virtual void updateSpeakerList();
|
||||
};
|
||||
|
||||
class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr>
|
||||
{
|
||||
public:
|
||||
LLActiveSpeakerMgr();
|
||||
protected:
|
||||
virtual void updateSpeakerList();
|
||||
};
|
||||
|
||||
class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLLocalSpeakerMgr>
|
||||
{
|
||||
public:
|
||||
LLLocalSpeakerMgr();
|
||||
~LLLocalSpeakerMgr ();
|
||||
protected:
|
||||
virtual void updateSpeakerList();
|
||||
};
|
||||
|
||||
class LLParticipantList;
|
||||
|
||||
class LLFloaterActiveSpeakers :
|
||||
public LLFloaterSingleton<LLFloaterActiveSpeakers>,
|
||||
@@ -199,107 +53,14 @@ public:
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
/*virtual*/ void draw();
|
||||
|
||||
/*virtual*/ void onChange();
|
||||
/*virtual*/ void onParticipantsChanged();
|
||||
|
||||
static void* createSpeakersPanel(void* data);
|
||||
|
||||
protected:
|
||||
LLFloaterActiveSpeakers(const LLSD& seed);
|
||||
|
||||
LLPanelActiveSpeakers* mPanel;
|
||||
LLParticipantList* mPanel;
|
||||
};
|
||||
|
||||
class LLPanelActiveSpeakers : public LLPanel
|
||||
{
|
||||
public:
|
||||
LLPanelActiveSpeakers(LLSpeakerMgr* data_source, BOOL show_text_chatters);
|
||||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
|
||||
void handleSpeakerSelect();
|
||||
void refreshSpeakers();
|
||||
|
||||
void setSpeaker(const LLUUID& id,
|
||||
const std::string& name = LLStringUtil::null,
|
||||
LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY,
|
||||
LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT);
|
||||
|
||||
void setVoiceModerationCtrlMode(const BOOL& moderated_voice);
|
||||
|
||||
static void onClickMuteVoiceCommit(LLUICtrl* ctrl, void* user_data);
|
||||
static void onClickMuteTextCommit(LLUICtrl* ctrl, void* user_data);
|
||||
static void onVolumeChange(LLUICtrl* source, void* user_data);
|
||||
static void onClickProfile(void* user_data);
|
||||
static void onDoubleClickSpeaker(void* user_data);
|
||||
static void onSortChanged(void* user_data);
|
||||
static void onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data);
|
||||
static void onModeratorMuteText(LLUICtrl* ctrl, void* user_data);
|
||||
static void onChangeModerationMode(LLUICtrl* ctrl, void* user_data);
|
||||
|
||||
protected:
|
||||
class SpeakerMuteListener : public LLOldEvents::LLSimpleListener
|
||||
{
|
||||
public:
|
||||
SpeakerMuteListener(LLPanelActiveSpeakers* panel) : mPanel(panel) {}
|
||||
|
||||
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
|
||||
LLPanelActiveSpeakers* mPanel;
|
||||
};
|
||||
|
||||
friend class SpeakerAddListener;
|
||||
class SpeakerAddListener : public LLOldEvents::LLSimpleListener
|
||||
{
|
||||
public:
|
||||
SpeakerAddListener(LLPanelActiveSpeakers* panel) : mPanel(panel) {}
|
||||
|
||||
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
|
||||
LLPanelActiveSpeakers* mPanel;
|
||||
};
|
||||
|
||||
friend class SpeakerRemoveListener;
|
||||
class SpeakerRemoveListener : public LLOldEvents::LLSimpleListener
|
||||
{
|
||||
public:
|
||||
SpeakerRemoveListener(LLPanelActiveSpeakers* panel) : mPanel(panel) {}
|
||||
|
||||
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
|
||||
LLPanelActiveSpeakers* mPanel;
|
||||
};
|
||||
|
||||
|
||||
friend class SpeakerClearListener;
|
||||
class SpeakerClearListener : public LLOldEvents::LLSimpleListener
|
||||
{
|
||||
public:
|
||||
SpeakerClearListener(LLPanelActiveSpeakers* panel) : mPanel(panel) {}
|
||||
|
||||
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
|
||||
LLPanelActiveSpeakers* mPanel;
|
||||
};
|
||||
|
||||
void addSpeaker(const LLUUID& id);
|
||||
void removeSpeaker(const LLUUID& id);
|
||||
|
||||
|
||||
LLScrollListCtrl* mSpeakerList;
|
||||
LLUICtrl* mMuteVoiceCtrl;
|
||||
LLUICtrl* mMuteTextCtrl;
|
||||
LLTextBox* mNameText;
|
||||
LLButton* mProfileBtn;
|
||||
BOOL mShowTextChatters;
|
||||
LLSpeakerMgr* mSpeakerMgr;
|
||||
LLFrameTimer mIconAnimationTimer;
|
||||
LLPointer<SpeakerMuteListener> mSpeakerMuteListener;
|
||||
LLPointer<SpeakerAddListener> mSpeakerAddListener;
|
||||
LLPointer<SpeakerRemoveListener> mSpeakerRemoveListener;
|
||||
LLPointer<SpeakerClearListener> mSpeakerClearListener;
|
||||
|
||||
CachedUICtrl<LLUICtrl> mVolumeSlider;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_LLFLOATERACTIVESPEAKERS_H
|
||||
|
||||
@@ -52,12 +52,13 @@
|
||||
#include "llagent.h"
|
||||
#include "llchatbar.h"
|
||||
#include "llconsole.h"
|
||||
#include "llfloateractivespeakers.h"
|
||||
#include "llfloaterchatterbox.h"
|
||||
#include "llfloatermute.h"
|
||||
#include "llfloaterscriptdebug.h"
|
||||
#include "lllogchat.h"
|
||||
#include "llmutelist.h"
|
||||
#include "llparticipantlist.h"
|
||||
#include "llspeakers.h"
|
||||
#include "llstylemap.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewermessage.h"
|
||||
@@ -126,7 +127,7 @@ void LLFloaterChat::draw()
|
||||
|
||||
BOOL LLFloaterChat::postBuild()
|
||||
{
|
||||
mPanel = (LLPanelActiveSpeakers*)getChild<LLPanel>("active_speakers_panel");
|
||||
mPanel = getChild<LLParticipantList>("active_speakers_panel");
|
||||
|
||||
LLChatBar* chat_barp = getChild<LLChatBar>("chat_panel", TRUE);
|
||||
if (chat_barp)
|
||||
@@ -324,7 +325,7 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file)
|
||||
// add objects as transient speakers that can be muted
|
||||
if (chat.mSourceType == CHAT_SOURCE_OBJECT)
|
||||
{
|
||||
chat_floater->mPanel->setSpeaker(chat.mFromID, chat.mFromName, LLSpeaker::STATUS_NOT_IN_CHANNEL, LLSpeaker::SPEAKER_OBJECT);
|
||||
LLLocalSpeakerMgr::getInstance()->setSpeaker(chat.mFromID, chat.mFromName, LLSpeaker::STATUS_NOT_IN_CHANNEL, LLSpeaker::SPEAKER_OBJECT);
|
||||
}
|
||||
|
||||
// start tab flashing on incoming text from other users (ignoring system text, etc)
|
||||
@@ -627,7 +628,7 @@ void LLFloaterChat::chatFromLogFile(LLLogChat::ELogLineType type , std::string l
|
||||
//static
|
||||
void* LLFloaterChat::createSpeakersPanel(void* data)
|
||||
{
|
||||
return new LLPanelActiveSpeakers(LLLocalSpeakerMgr::getInstance(), TRUE);
|
||||
return new LLParticipantList(LLLocalSpeakerMgr::getInstance(), true);
|
||||
}
|
||||
|
||||
//static
|
||||
|
||||
@@ -48,7 +48,7 @@ class LLViewerTextEditor;
|
||||
class LLMessageSystem;
|
||||
class LLUUID;
|
||||
class LLCheckBoxCtrl;
|
||||
class LLPanelActiveSpeakers;
|
||||
class LLParticipantList;
|
||||
class LLLogChat;
|
||||
class LLChatBar;
|
||||
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
static void show(LLFloater* instance, const LLSD& key);
|
||||
static void hide(LLFloater* instance, const LLSD& key);
|
||||
|
||||
LLPanelActiveSpeakers* mPanel;
|
||||
LLParticipantList* mPanel;
|
||||
BOOL mScrolledToEnd;
|
||||
|
||||
BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE );
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "llfloaterchat.h"
|
||||
#include "llfloaterfriends.h"
|
||||
#include "llfloatergroups.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "llimview.h"
|
||||
#include "llimpanel.h"
|
||||
#include "llstring.h"
|
||||
@@ -315,7 +315,7 @@ void LLFloaterChatterBox::addFloater(LLFloater* floaterp,
|
||||
//static
|
||||
LLFloater* LLFloaterChatterBox::getCurrentVoiceFloater()
|
||||
{
|
||||
if (!LLVoiceClient::voiceEnabled())
|
||||
if (!LLVoiceClient::getInstance()->voiceEnabled())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,348 +0,0 @@
|
||||
/**
|
||||
* @file llfloatervoicedevicesettings.cpp
|
||||
* @author Richard Nelson
|
||||
* @brief Voice communication set-up
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloatervoicedevicesettings.h"
|
||||
|
||||
// Viewer includes
|
||||
#include "llagent.h"
|
||||
#include "llbutton.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llfocusmgr.h"
|
||||
#include "lliconctrl.h"
|
||||
#include "llprefsvoice.h"
|
||||
#include "llsliderctrl.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llvoiceclient.h"
|
||||
#include "llimpanel.h"
|
||||
|
||||
// Library includes (after viewer)
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
|
||||
LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings()
|
||||
{
|
||||
mCtrlInputDevices = NULL;
|
||||
mCtrlOutputDevices = NULL;
|
||||
mInputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
|
||||
mOutputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
|
||||
mDevicesUpdated = FALSE;
|
||||
|
||||
// grab "live" mic volume level
|
||||
mMicVolume = gSavedSettings.getF32("AudioLevelMic");
|
||||
|
||||
// ask for new device enumeration
|
||||
// now do this in onOpen() instead...
|
||||
//gVoiceClient->refreshDeviceLists();
|
||||
}
|
||||
|
||||
LLPanelVoiceDeviceSettings::~LLPanelVoiceDeviceSettings()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLPanelVoiceDeviceSettings::postBuild()
|
||||
{
|
||||
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
|
||||
// set mic volume tuning slider based on last mic volume setting
|
||||
volume_slider->setValue(mMicVolume);
|
||||
|
||||
childSetCommitCallback("voice_input_device", onCommitInputDevice, this);
|
||||
childSetCommitCallback("voice_output_device", onCommitOutputDevice, this);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::draw()
|
||||
{
|
||||
// let user know that volume indicator is not yet available
|
||||
bool is_in_tuning_mode = gVoiceClient->inTuningMode();
|
||||
childSetVisible("wait_text", !is_in_tuning_mode);
|
||||
|
||||
LLPanel::draw();
|
||||
|
||||
F32 voice_power = gVoiceClient->tuningGetEnergy();
|
||||
S32 discrete_power = 0;
|
||||
|
||||
if (!is_in_tuning_mode)
|
||||
{
|
||||
discrete_power = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
discrete_power = llmin(4, llfloor((voice_power / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 4.f));
|
||||
}
|
||||
|
||||
if (is_in_tuning_mode)
|
||||
{
|
||||
for(S32 power_bar_idx = 0; power_bar_idx < 5; power_bar_idx++)
|
||||
{
|
||||
std::string view_name = llformat("%s%d", "bar", power_bar_idx);
|
||||
LLView* bar_view = getChild<LLView>(view_name);
|
||||
if (bar_view)
|
||||
{
|
||||
if (power_bar_idx < discrete_power)
|
||||
{
|
||||
LLColor4 color = (power_bar_idx >= 3) ? gSavedSettings.getColor4("OverdrivenColor") : gSavedSettings.getColor4("SpeakingColor");
|
||||
gl_rect_2d(bar_view->getRect(), color, TRUE);
|
||||
}
|
||||
gl_rect_2d(bar_view->getRect(), LLColor4::grey, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::apply()
|
||||
{
|
||||
std::string s;
|
||||
if(mCtrlInputDevices)
|
||||
{
|
||||
s = mCtrlInputDevices->getSimple();
|
||||
gSavedSettings.setString("VoiceInputAudioDevice", s);
|
||||
mInputDevice = s;
|
||||
}
|
||||
|
||||
if(mCtrlOutputDevices)
|
||||
{
|
||||
s = mCtrlOutputDevices->getSimple();
|
||||
gSavedSettings.setString("VoiceOutputAudioDevice", s);
|
||||
mOutputDevice = s;
|
||||
}
|
||||
|
||||
// assume we are being destroyed by closing our embedding window
|
||||
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
|
||||
if(volume_slider)
|
||||
{
|
||||
F32 slider_value = (F32)volume_slider->getValue().asReal();
|
||||
gSavedSettings.setF32("AudioLevelMic", slider_value);
|
||||
mMicVolume = slider_value;
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::cancel()
|
||||
{
|
||||
gSavedSettings.setString("VoiceInputAudioDevice", mInputDevice);
|
||||
gSavedSettings.setString("VoiceOutputAudioDevice", mOutputDevice);
|
||||
|
||||
if(mCtrlInputDevices)
|
||||
mCtrlInputDevices->setSimple(mInputDevice);
|
||||
|
||||
if(mCtrlOutputDevices)
|
||||
mCtrlOutputDevices->setSimple(mOutputDevice);
|
||||
|
||||
gSavedSettings.setF32("AudioLevelMic", mMicVolume);
|
||||
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
|
||||
if(volume_slider)
|
||||
{
|
||||
volume_slider->setValue(mMicVolume);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::refresh()
|
||||
{
|
||||
//grab current volume
|
||||
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
|
||||
// set mic volume tuning slider based on last mic volume setting
|
||||
F32 current_volume = (F32)volume_slider->getValue().asReal();
|
||||
gVoiceClient->tuningSetMicVolume(current_volume);
|
||||
|
||||
// Fill in popup menus
|
||||
mCtrlInputDevices = getChild<LLComboBox>("voice_input_device");
|
||||
mCtrlOutputDevices = getChild<LLComboBox>("voice_output_device");
|
||||
|
||||
if(!gVoiceClient->deviceSettingsAvailable())
|
||||
{
|
||||
// The combo boxes are disabled, since we can't get the device settings from the daemon just now.
|
||||
// Put the currently set default (ONLY) in the box, and select it.
|
||||
if(mCtrlInputDevices)
|
||||
{
|
||||
mCtrlInputDevices->removeall();
|
||||
mCtrlInputDevices->add( mInputDevice, ADD_BOTTOM );
|
||||
mCtrlInputDevices->setSimple(mInputDevice);
|
||||
}
|
||||
if(mCtrlOutputDevices)
|
||||
{
|
||||
mCtrlOutputDevices->removeall();
|
||||
mCtrlOutputDevices->add( mOutputDevice, ADD_BOTTOM );
|
||||
mCtrlOutputDevices->setSimple(mOutputDevice);
|
||||
}
|
||||
}
|
||||
else if (!mDevicesUpdated)
|
||||
{
|
||||
LLVoiceClient::deviceList *devices;
|
||||
|
||||
LLVoiceClient::deviceList::iterator iter;
|
||||
|
||||
if(mCtrlInputDevices)
|
||||
{
|
||||
mCtrlInputDevices->removeall();
|
||||
mCtrlInputDevices->add( getString("default_text"), ADD_BOTTOM );
|
||||
|
||||
devices = gVoiceClient->getCaptureDevices();
|
||||
for(iter=devices->begin(); iter != devices->end(); iter++)
|
||||
{
|
||||
mCtrlInputDevices->add( *iter, ADD_BOTTOM );
|
||||
}
|
||||
|
||||
if(!mCtrlInputDevices->setSimple(mInputDevice))
|
||||
{
|
||||
mCtrlInputDevices->setSimple(getString("default_text"));
|
||||
}
|
||||
}
|
||||
|
||||
if(mCtrlOutputDevices)
|
||||
{
|
||||
mCtrlOutputDevices->removeall();
|
||||
mCtrlOutputDevices->add( getString("default_text"), ADD_BOTTOM );
|
||||
|
||||
devices = gVoiceClient->getRenderDevices();
|
||||
for(iter=devices->begin(); iter != devices->end(); iter++)
|
||||
{
|
||||
mCtrlOutputDevices->add( *iter, ADD_BOTTOM );
|
||||
}
|
||||
|
||||
if(!mCtrlOutputDevices->setSimple(mOutputDevice))
|
||||
{
|
||||
mCtrlOutputDevices->setSimple(getString("default_text"));
|
||||
}
|
||||
}
|
||||
mDevicesUpdated = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::onOpen()
|
||||
{
|
||||
mInputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
|
||||
mOutputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
|
||||
mMicVolume = gSavedSettings.getF32("AudioLevelMic");
|
||||
mDevicesUpdated = FALSE;
|
||||
|
||||
// ask for new device enumeration
|
||||
gVoiceClient->refreshDeviceLists();
|
||||
|
||||
// put voice client in "tuning" mode
|
||||
gVoiceClient->tuningStart();
|
||||
LLVoiceChannel::suspend();
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::onClose(bool app_quitting)
|
||||
{
|
||||
gVoiceClient->tuningStop();
|
||||
LLVoiceChannel::resume();
|
||||
}
|
||||
|
||||
// static
|
||||
void LLPanelVoiceDeviceSettings::onCommitInputDevice(LLUICtrl* ctrl, void* user_data)
|
||||
{
|
||||
if(gVoiceClient)
|
||||
{
|
||||
gVoiceClient->setCaptureDevice(ctrl->getValue().asString());
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLPanelVoiceDeviceSettings::onCommitOutputDevice(LLUICtrl* ctrl, void* user_data)
|
||||
{
|
||||
if(gVoiceClient)
|
||||
{
|
||||
gVoiceClient->setRenderDevice(ctrl->getValue().asString());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLFloaterVoiceDeviceSettings
|
||||
//
|
||||
|
||||
LLFloaterVoiceDeviceSettings::LLFloaterVoiceDeviceSettings(const LLSD& seed)
|
||||
: LLFloater(std::string("floater_device_settings")),
|
||||
mDevicePanel(NULL)
|
||||
{
|
||||
mFactoryMap["device_settings"] = LLCallbackMap(createPanelVoiceDeviceSettings, this);
|
||||
// do not automatically open singleton floaters (as result of getInstance())
|
||||
BOOL no_open = FALSE;
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_device_settings.xml", &mFactoryMap, no_open);
|
||||
center();
|
||||
}
|
||||
|
||||
void LLFloaterVoiceDeviceSettings::onOpen()
|
||||
{
|
||||
if(mDevicePanel)
|
||||
{
|
||||
mDevicePanel->onOpen();
|
||||
}
|
||||
|
||||
LLFloater::onOpen();
|
||||
}
|
||||
|
||||
void LLFloaterVoiceDeviceSettings::onClose(bool app_quitting)
|
||||
{
|
||||
if(mDevicePanel)
|
||||
{
|
||||
mDevicePanel->onClose(app_quitting);
|
||||
}
|
||||
|
||||
setVisible(FALSE);
|
||||
}
|
||||
|
||||
void LLFloaterVoiceDeviceSettings::apply()
|
||||
{
|
||||
if (mDevicePanel)
|
||||
{
|
||||
mDevicePanel->apply();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterVoiceDeviceSettings::cancel()
|
||||
{
|
||||
if (mDevicePanel)
|
||||
{
|
||||
mDevicePanel->cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterVoiceDeviceSettings::draw()
|
||||
{
|
||||
if (mDevicePanel)
|
||||
{
|
||||
mDevicePanel->refresh();
|
||||
}
|
||||
LLFloater::draw();
|
||||
}
|
||||
|
||||
// static
|
||||
void* LLFloaterVoiceDeviceSettings::createPanelVoiceDeviceSettings(void* user_data)
|
||||
{
|
||||
LLFloaterVoiceDeviceSettings* floaterp = (LLFloaterVoiceDeviceSettings*)user_data;
|
||||
floaterp->mDevicePanel = new LLPanelVoiceDeviceSettings();
|
||||
return floaterp->mDevicePanel;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* @file llpanelvoicedevicesettings.h
|
||||
* @author Richard Nelson
|
||||
* @brief Voice communication set-up wizard
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERVOICEDEVICESETTINGS_H
|
||||
#define LL_LLFLOATERVOICEDEVICESETTINGS_H
|
||||
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLPrefsVoiceLogic;
|
||||
|
||||
class LLPanelVoiceDeviceSettings : public LLPanel
|
||||
{
|
||||
public:
|
||||
LLPanelVoiceDeviceSettings();
|
||||
~LLPanelVoiceDeviceSettings();
|
||||
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ BOOL postBuild();
|
||||
void apply();
|
||||
void cancel();
|
||||
void refresh();
|
||||
void onOpen();
|
||||
void onClose(bool app_quitting);
|
||||
|
||||
protected:
|
||||
static void onCommitInputDevice(LLUICtrl* ctrl, void* user_data);
|
||||
static void onCommitOutputDevice(LLUICtrl* ctrl, void* user_data);
|
||||
|
||||
F32 mMicVolume;
|
||||
std::string mInputDevice;
|
||||
std::string mOutputDevice;
|
||||
class LLComboBox *mCtrlInputDevices;
|
||||
class LLComboBox *mCtrlOutputDevices;
|
||||
BOOL mDevicesUpdated;
|
||||
};
|
||||
|
||||
class LLFloaterVoiceDeviceSettings : public LLFloater, public LLFloaterSingleton<LLFloaterVoiceDeviceSettings>
|
||||
{
|
||||
public:
|
||||
LLFloaterVoiceDeviceSettings(const LLSD& seed);
|
||||
/*virtual*/ void onOpen();
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
/*virtual*/ void draw();
|
||||
void apply();
|
||||
void cancel();
|
||||
|
||||
protected:
|
||||
static void* createPanelVoiceDeviceSettings(void* user_data);
|
||||
|
||||
LLPanelVoiceDeviceSettings* mDevicePanel;
|
||||
};
|
||||
|
||||
#endif // LL_LLFLOATERVOICEDEVICESETTINGS_H
|
||||
@@ -28,7 +28,7 @@
|
||||
#define LL_LLGROUPACTIONS_H
|
||||
|
||||
class LLFloaterGroupInfo;
|
||||
struct LLOfferInfo;
|
||||
class LLOfferInfo;
|
||||
|
||||
/**
|
||||
* Group-related actions (join, leave, new, delete, etc)
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
* @brief LLIMPanel class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
@@ -51,9 +50,7 @@
|
||||
#include "llchat.h"
|
||||
#include "llconsole.h"
|
||||
#include "llgroupactions.h"
|
||||
#include "llfloateractivespeakers.h"
|
||||
#include "llfloaterchat.h"
|
||||
#include "llfloatergroupinfo.h"
|
||||
#include "llimview.h"
|
||||
#include "llinventory.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
@@ -62,7 +59,9 @@
|
||||
#include "llkeyboard.h"
|
||||
#include "lllineeditor.h"
|
||||
#include "llnotify.h"
|
||||
#include "llparticipantlist.h"
|
||||
#include "llresmgr.h"
|
||||
#include "llspeakers.h"
|
||||
#include "lltrans.h"
|
||||
#include "lltabcontainer.h"
|
||||
#include "llviewertexteditor.h"
|
||||
@@ -71,6 +70,7 @@
|
||||
#include "llviewercontrol.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "lllogchat.h"
|
||||
#include "llweb.h"
|
||||
#include "llhttpclient.h"
|
||||
@@ -86,7 +86,6 @@
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy startConferenceChatResponder_timeout;
|
||||
extern AIHTTPTimeoutPolicy voiceCallCapResponder_timeout;
|
||||
extern AIHTTPTimeoutPolicy sessionInviteResponder_timeout;
|
||||
|
||||
//
|
||||
@@ -95,7 +94,6 @@ extern AIHTTPTimeoutPolicy sessionInviteResponder_timeout;
|
||||
const S32 LINE_HEIGHT = 16;
|
||||
const S32 MIN_WIDTH = 200;
|
||||
const S32 MIN_HEIGHT = 130;
|
||||
const U32 DEFAULT_RETRIES_COUNT = 3;
|
||||
|
||||
//
|
||||
// Statics
|
||||
@@ -105,13 +103,6 @@ static std::string sTitleString = "Instant Message with [NAME]";
|
||||
static std::string sTypingStartString = "[NAME]: ...";
|
||||
static std::string sSessionStartString = "Starting session with [NAME] please wait.";
|
||||
|
||||
LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
|
||||
LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
|
||||
LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
|
||||
LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
|
||||
|
||||
BOOL LLVoiceChannel::sSuspended = FALSE;
|
||||
|
||||
void session_starter_helper(
|
||||
const LLUUID& temp_session_id,
|
||||
const LLUUID& other_participant_id,
|
||||
@@ -300,792 +291,6 @@ bool send_start_session_messages(
|
||||
return false;
|
||||
}
|
||||
|
||||
class LLVoiceCallCapResponder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {};
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason); // called with bad status codes
|
||||
/*virtual*/ void result(const LLSD& content);
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return voiceCallCapResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "LLVoiceCallCapResponder"; }
|
||||
|
||||
private:
|
||||
LLUUID mSessionID;
|
||||
};
|
||||
|
||||
|
||||
void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
|
||||
{
|
||||
llwarns << "LLVoiceCallCapResponder::error("
|
||||
<< status << ": " << reason << ")"
|
||||
<< llendl;
|
||||
LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
|
||||
if ( channelp )
|
||||
{
|
||||
if ( 403 == status )
|
||||
{
|
||||
//403 == no ability
|
||||
LLNotifications::instance().add(
|
||||
"VoiceNotAllowed",
|
||||
channelp->getNotifyArgs());
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotifications::instance().add(
|
||||
"VoiceCallGenericError",
|
||||
channelp->getNotifyArgs());
|
||||
}
|
||||
channelp->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceCallCapResponder::result(const LLSD& content)
|
||||
{
|
||||
LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
|
||||
if (channelp)
|
||||
{
|
||||
// *TODO: DEBUG SPAM
|
||||
LLSD::map_const_iterator iter;
|
||||
for(iter = content.beginMap(); iter != content.endMap(); ++iter)
|
||||
{
|
||||
llinfos << "LLVoiceCallCapResponder::result got "
|
||||
<< iter->first << llendl;
|
||||
}
|
||||
|
||||
channelp->setChannelInfo(
|
||||
content["voice_credentials"]["channel_uri"].asString(),
|
||||
content["voice_credentials"]["channel_credentials"].asString());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLVoiceChannel
|
||||
//
|
||||
LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :
|
||||
mSessionID(session_id),
|
||||
mState(STATE_NO_CHANNEL_INFO),
|
||||
mSessionName(session_name),
|
||||
mIgnoreNextSessionLeave(FALSE)
|
||||
{
|
||||
mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName;
|
||||
|
||||
if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second)
|
||||
{
|
||||
// a voice channel already exists for this session id, so this instance will be orphaned
|
||||
// the end result should simply be the failure to make voice calls
|
||||
llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl;
|
||||
}
|
||||
|
||||
LLVoiceClient::getInstance()->addObserver(this);
|
||||
}
|
||||
|
||||
LLVoiceChannel::~LLVoiceChannel()
|
||||
{
|
||||
// Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed.
|
||||
if(gVoiceClient)
|
||||
{
|
||||
gVoiceClient->removeObserver(this);
|
||||
}
|
||||
|
||||
sVoiceChannelMap.erase(mSessionID);
|
||||
sVoiceChannelURIMap.erase(mURI);
|
||||
}
|
||||
|
||||
void LLVoiceChannel::setChannelInfo(
|
||||
const std::string& uri,
|
||||
const std::string& credentials)
|
||||
{
|
||||
setURI(uri);
|
||||
|
||||
mCredentials = credentials;
|
||||
|
||||
if (mState == STATE_NO_CHANNEL_INFO)
|
||||
{
|
||||
if (mURI.empty())
|
||||
{
|
||||
LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
|
||||
llwarns << "Received empty URI for channel " << mSessionName << llendl;
|
||||
deactivate();
|
||||
}
|
||||
else if (mCredentials.empty())
|
||||
{
|
||||
LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
|
||||
llwarns << "Received empty credentials for channel " << mSessionName << llendl;
|
||||
deactivate();
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(STATE_READY);
|
||||
|
||||
// if we are supposed to be active, reconnect
|
||||
// this will happen on initial connect, as we request credentials on first use
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
// just in case we got new channel info while active
|
||||
// should move over to new channel
|
||||
activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal)
|
||||
{
|
||||
if (channelURI != mURI)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type < BEGIN_ERROR_STATUS)
|
||||
{
|
||||
handleStatusChange(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
handleError(type);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannel::handleStatusChange(EStatusType type)
|
||||
{
|
||||
// status updates
|
||||
switch(type)
|
||||
{
|
||||
case STATUS_LOGIN_RETRY:
|
||||
//mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle();
|
||||
LLNotificationsUtil::add("VoiceLoginRetry");
|
||||
break;
|
||||
case STATUS_LOGGED_IN:
|
||||
//if (!mLoginNotificationHandle.isDead())
|
||||
//{
|
||||
// LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get();
|
||||
// if (notifyp)
|
||||
// {
|
||||
// notifyp->close();
|
||||
// }
|
||||
// mLoginNotificationHandle.markDead();
|
||||
//}
|
||||
break;
|
||||
case STATUS_LEFT_CHANNEL:
|
||||
if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
|
||||
{
|
||||
// if forceably removed from channel
|
||||
// update the UI and revert to default channel
|
||||
LLNotificationsUtil::add("VoiceChannelDisconnected", mNotifyArgs);
|
||||
deactivate();
|
||||
}
|
||||
mIgnoreNextSessionLeave = FALSE;
|
||||
break;
|
||||
case STATUS_JOINING:
|
||||
if (callStarted())
|
||||
{
|
||||
setState(STATE_RINGING);
|
||||
}
|
||||
break;
|
||||
case STATUS_JOINED:
|
||||
if (callStarted())
|
||||
{
|
||||
setState(STATE_CONNECTED);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// default behavior is to just deactivate channel
|
||||
// derived classes provide specific error messages
|
||||
void LLVoiceChannel::handleError(EStatusType type)
|
||||
{
|
||||
deactivate();
|
||||
setState(STATE_ERROR);
|
||||
}
|
||||
|
||||
BOOL LLVoiceChannel::isActive()
|
||||
{
|
||||
// only considered active when currently bound channel matches what our channel
|
||||
return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;
|
||||
}
|
||||
|
||||
BOOL LLVoiceChannel::callStarted()
|
||||
{
|
||||
return mState >= STATE_CALL_STARTED;
|
||||
}
|
||||
|
||||
void LLVoiceChannel::deactivate()
|
||||
{
|
||||
if (mState >= STATE_RINGING)
|
||||
{
|
||||
// ignore session leave event
|
||||
mIgnoreNextSessionLeave = TRUE;
|
||||
}
|
||||
|
||||
if (callStarted())
|
||||
{
|
||||
setState(STATE_HUNG_UP);
|
||||
// mute the microphone if required when returning to the proximal channel
|
||||
if (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this)
|
||||
{
|
||||
gSavedSettings.setBOOL("PTTCurrentlyEnabled", true);
|
||||
}
|
||||
}
|
||||
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
// default channel is proximal channel
|
||||
sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
|
||||
sCurrentVoiceChannel->activate();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannel::activate()
|
||||
{
|
||||
if (callStarted())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// deactivate old channel and mark ourselves as the active one
|
||||
if (sCurrentVoiceChannel != this)
|
||||
{
|
||||
// mark as current before deactivating the old channel to prevent
|
||||
// activating the proximal channel between IM calls
|
||||
LLVoiceChannel* old_channel = sCurrentVoiceChannel;
|
||||
sCurrentVoiceChannel = this;
|
||||
if (old_channel)
|
||||
{
|
||||
old_channel->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
if (mState == STATE_NO_CHANNEL_INFO)
|
||||
{
|
||||
// responsible for setting status to active
|
||||
getChannelInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(STATE_CALL_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannel::getChannelInfo()
|
||||
{
|
||||
// pretend we have everything we need
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
setState(STATE_CALL_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id)
|
||||
{
|
||||
voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id);
|
||||
if (found_it == sVoiceChannelMap.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return found_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)
|
||||
{
|
||||
voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri);
|
||||
if (found_it == sVoiceChannelURIMap.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return found_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
|
||||
{
|
||||
sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
|
||||
mSessionID = new_session_id;
|
||||
sVoiceChannelMap.insert(std::make_pair(mSessionID, this));
|
||||
}
|
||||
|
||||
void LLVoiceChannel::setURI(std::string uri)
|
||||
{
|
||||
sVoiceChannelURIMap.erase(mURI);
|
||||
mURI = uri;
|
||||
sVoiceChannelURIMap.insert(std::make_pair(mURI, this));
|
||||
}
|
||||
|
||||
void LLVoiceChannel::setState(EState state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case STATE_RINGING:
|
||||
gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
|
||||
break;
|
||||
case STATE_CONNECTED:
|
||||
gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs);
|
||||
break;
|
||||
case STATE_HUNG_UP:
|
||||
gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mState = state;
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
void LLVoiceChannel::initClass()
|
||||
{
|
||||
sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
void LLVoiceChannel::suspend()
|
||||
{
|
||||
if (!sSuspended)
|
||||
{
|
||||
sSuspendedVoiceChannel = sCurrentVoiceChannel;
|
||||
sSuspended = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVoiceChannel::resume()
|
||||
{
|
||||
if (sSuspended)
|
||||
{
|
||||
if (gVoiceClient->voiceEnabled())
|
||||
{
|
||||
if (sSuspendedVoiceChannel)
|
||||
{
|
||||
sSuspendedVoiceChannel->activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVoiceChannelProximal::getInstance()->activate();
|
||||
}
|
||||
}
|
||||
sSuspended = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLVoiceChannelGroup
|
||||
//
|
||||
|
||||
LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :
|
||||
LLVoiceChannel(session_id, session_name)
|
||||
{
|
||||
mRetries = DEFAULT_RETRIES_COUNT;
|
||||
mIsRetrying = FALSE;
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::deactivate()
|
||||
{
|
||||
if (callStarted())
|
||||
{
|
||||
LLVoiceClient::getInstance()->leaveNonSpatialChannel();
|
||||
}
|
||||
LLVoiceChannel::deactivate();
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::activate()
|
||||
{
|
||||
if (callStarted()) return;
|
||||
|
||||
LLVoiceChannel::activate();
|
||||
|
||||
if (callStarted())
|
||||
{
|
||||
// we have the channel info, just need to use it now
|
||||
LLVoiceClient::getInstance()->setNonSpatialChannel(
|
||||
mURI,
|
||||
mCredentials);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::getChannelInfo()
|
||||
{
|
||||
LLViewerRegion* region = gAgent.getRegion();
|
||||
if (region)
|
||||
{
|
||||
std::string url = region->getCapability("ChatSessionRequest");
|
||||
LLSD data;
|
||||
data["method"] = "call";
|
||||
data["session-id"] = mSessionID;
|
||||
LLHTTPClient::post(url,
|
||||
data,
|
||||
new LLVoiceCallCapResponder(mSessionID));
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::setChannelInfo(
|
||||
const std::string& uri,
|
||||
const std::string& credentials)
|
||||
{
|
||||
setURI(uri);
|
||||
|
||||
mCredentials = credentials;
|
||||
|
||||
if (mState == STATE_NO_CHANNEL_INFO)
|
||||
{
|
||||
if(!mURI.empty() && !mCredentials.empty())
|
||||
{
|
||||
setState(STATE_READY);
|
||||
|
||||
// if we are supposed to be active, reconnect
|
||||
// this will happen on initial connect, as we request credentials on first use
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
// just in case we got new channel info while active
|
||||
// should move over to new channel
|
||||
activate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// *TODO: notify user
|
||||
llwarns << "Received invalid credentials for channel " << mSessionName << llendl;
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
else if ( mIsRetrying )
|
||||
{
|
||||
// we have the channel info, just need to use it now
|
||||
LLVoiceClient::getInstance()->setNonSpatialChannel(
|
||||
mURI,
|
||||
mCredentials);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::handleStatusChange(EStatusType type)
|
||||
{
|
||||
// status updates
|
||||
switch(type)
|
||||
{
|
||||
case STATUS_JOINED:
|
||||
mRetries = 3;
|
||||
mIsRetrying = FALSE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleStatusChange(type);
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::handleError(EStatusType status)
|
||||
{
|
||||
std::string notify;
|
||||
switch(status)
|
||||
{
|
||||
case ERROR_CHANNEL_LOCKED:
|
||||
case ERROR_CHANNEL_FULL:
|
||||
notify = "VoiceChannelFull";
|
||||
break;
|
||||
case ERROR_NOT_AVAILABLE:
|
||||
//clear URI and credentials
|
||||
//set the state to be no info
|
||||
//and activate
|
||||
if ( mRetries > 0 )
|
||||
{
|
||||
mRetries--;
|
||||
mIsRetrying = TRUE;
|
||||
mIgnoreNextSessionLeave = TRUE;
|
||||
|
||||
getChannelInfo();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
notify = "VoiceChannelJoinFailed";
|
||||
mRetries = DEFAULT_RETRIES_COUNT;
|
||||
mIsRetrying = FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ERROR_UNKNOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// notification
|
||||
if (!notify.empty())
|
||||
{
|
||||
LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs);
|
||||
// echo to im window
|
||||
gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage());
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleError(status);
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::setState(EState state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case STATE_RINGING:
|
||||
if ( !mIsRetrying )
|
||||
{
|
||||
gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
|
||||
}
|
||||
|
||||
mState = state;
|
||||
break;
|
||||
default:
|
||||
LLVoiceChannel::setState(state);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLVoiceChannelProximal
|
||||
//
|
||||
LLVoiceChannelProximal::LLVoiceChannelProximal() :
|
||||
LLVoiceChannel(LLUUID::null, LLStringUtil::null)
|
||||
{
|
||||
activate();
|
||||
}
|
||||
|
||||
BOOL LLVoiceChannelProximal::isActive()
|
||||
{
|
||||
return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();
|
||||
}
|
||||
|
||||
void LLVoiceChannelProximal::activate()
|
||||
{
|
||||
if (callStarted()) return;
|
||||
|
||||
LLVoiceChannel::activate();
|
||||
|
||||
if (callStarted())
|
||||
{
|
||||
// this implicitly puts you back in the spatial channel
|
||||
LLVoiceClient::getInstance()->leaveNonSpatialChannel();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal)
|
||||
{
|
||||
if (!proximal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type < BEGIN_ERROR_STATUS)
|
||||
{
|
||||
handleStatusChange(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
handleError(type);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
|
||||
{
|
||||
// status updates
|
||||
switch(status)
|
||||
{
|
||||
case STATUS_LEFT_CHANNEL:
|
||||
// do not notify user when leaving proximal channel
|
||||
return;
|
||||
case STATUS_VOICE_DISABLED:
|
||||
gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LLVoiceChannel::handleStatusChange(status);
|
||||
}
|
||||
|
||||
|
||||
void LLVoiceChannelProximal::handleError(EStatusType status)
|
||||
{
|
||||
std::string notify;
|
||||
switch(status)
|
||||
{
|
||||
case ERROR_CHANNEL_LOCKED:
|
||||
case ERROR_CHANNEL_FULL:
|
||||
notify = "ProximalVoiceChannelFull";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// notification
|
||||
if (!notify.empty())
|
||||
{
|
||||
LLNotifications::instance().add(notify, mNotifyArgs);
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleError(status);
|
||||
}
|
||||
|
||||
void LLVoiceChannelProximal::deactivate()
|
||||
{
|
||||
if (callStarted())
|
||||
{
|
||||
setState(STATE_HUNG_UP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLVoiceChannelP2P
|
||||
//
|
||||
LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :
|
||||
LLVoiceChannelGroup(session_id, session_name),
|
||||
mOtherUserID(other_user_id),
|
||||
mReceivedCall(FALSE)
|
||||
{
|
||||
// make sure URI reflects encoded version of other user's agent id
|
||||
setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
|
||||
{
|
||||
// status updates
|
||||
switch(type)
|
||||
{
|
||||
case STATUS_LEFT_CHANNEL:
|
||||
if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
|
||||
{
|
||||
if (mState == STATE_RINGING)
|
||||
{
|
||||
// other user declined call
|
||||
LLNotificationsUtil::add("P2PCallDeclined", mNotifyArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// other user hung up
|
||||
LLNotificationsUtil::add("VoiceChannelDisconnectedP2P", mNotifyArgs);
|
||||
}
|
||||
deactivate();
|
||||
}
|
||||
mIgnoreNextSessionLeave = FALSE;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleStatusChange(type);
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::handleError(EStatusType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ERROR_NOT_AVAILABLE:
|
||||
LLNotificationsUtil::add("P2PCallNoAnswer", mNotifyArgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleError(type);
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::activate()
|
||||
{
|
||||
if (callStarted()) return;
|
||||
|
||||
LLVoiceChannel::activate();
|
||||
|
||||
if (callStarted())
|
||||
{
|
||||
// no session handle yet, we're starting the call
|
||||
if (mSessionHandle.empty())
|
||||
{
|
||||
mReceivedCall = FALSE;
|
||||
LLVoiceClient::getInstance()->callUser(mOtherUserID);
|
||||
}
|
||||
// otherwise answering the call
|
||||
else
|
||||
{
|
||||
LLVoiceClient::getInstance()->answerInvite(mSessionHandle);
|
||||
|
||||
// using the session handle invalidates it. Clear it out here so we can't reuse it by accident.
|
||||
mSessionHandle.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::getChannelInfo()
|
||||
{
|
||||
// pretend we have everything we need, since P2P doesn't use channel info
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
setState(STATE_CALL_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
// receiving session from other user who initiated call
|
||||
void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI)
|
||||
{
|
||||
BOOL needs_activate = FALSE;
|
||||
if (callStarted())
|
||||
{
|
||||
// defer to lower agent id when already active
|
||||
if (mOtherUserID < gAgent.getID())
|
||||
{
|
||||
// pretend we haven't started the call yet, so we can connect to this session instead
|
||||
deactivate();
|
||||
needs_activate = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are active and have priority, invite the other user again
|
||||
// under the assumption they will join this new session
|
||||
mSessionHandle.clear();
|
||||
LLVoiceClient::getInstance()->callUser(mOtherUserID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mSessionHandle = handle;
|
||||
|
||||
// The URI of a p2p session should always be the other end's SIP URI.
|
||||
if(!inURI.empty())
|
||||
{
|
||||
setURI(inURI);
|
||||
}
|
||||
else
|
||||
{
|
||||
setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
|
||||
}
|
||||
|
||||
mReceivedCall = TRUE;
|
||||
|
||||
if (needs_activate)
|
||||
{
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::setState(EState state)
|
||||
{
|
||||
// you only "answer" voice invites in p2p mode
|
||||
// so provide a special purpose message here
|
||||
if (mReceivedCall && state == STATE_RINGING)
|
||||
{
|
||||
gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs);
|
||||
mState = state;
|
||||
return;
|
||||
}
|
||||
LLVoiceChannel::setState(state);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLFloaterIMPanel
|
||||
@@ -1310,13 +515,13 @@ LLFloaterIMPanel::~LLFloaterIMPanel()
|
||||
mSpeakers = NULL;
|
||||
|
||||
// End the text IM session if necessary
|
||||
if(gVoiceClient && mOtherParticipantUUID.notNull())
|
||||
if(LLVoiceClient::instanceExists() && mOtherParticipantUUID.notNull())
|
||||
{
|
||||
switch(mDialog)
|
||||
{
|
||||
case IM_NOTHING_SPECIAL:
|
||||
case IM_SESSION_P2P_INVITE:
|
||||
gVoiceClient->endUserIMSession(mOtherParticipantUUID);
|
||||
LLVoiceClient::getInstance()->endUserIMSession(mOtherParticipantUUID);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1416,7 +621,7 @@ BOOL LLFloaterIMPanel::postBuild()
|
||||
void* LLFloaterIMPanel::createSpeakersPanel(void* data)
|
||||
{
|
||||
LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)data;
|
||||
floaterp->mSpeakerPanel = new LLPanelActiveSpeakers(floaterp->mSpeakers, TRUE);
|
||||
floaterp->mSpeakerPanel = new LLParticipantList(floaterp->mSpeakers, true);
|
||||
return floaterp->mSpeakerPanel;
|
||||
}
|
||||
|
||||
@@ -1446,7 +651,7 @@ void LLFloaterIMPanel::onVolumeChange(LLUICtrl* source, void* user_data)
|
||||
LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data;
|
||||
if (floaterp)
|
||||
{
|
||||
gVoiceClient->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal());
|
||||
LLVoiceClient::getInstance()->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1458,12 +663,12 @@ void LLFloaterIMPanel::draw()
|
||||
|
||||
BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "")
|
||||
&& mSessionInitialized
|
||||
&& LLVoiceClient::voiceEnabled()
|
||||
&& LLVoiceClient::getInstance()->voiceEnabled()
|
||||
&& mCallBackEnabled;
|
||||
|
||||
// hide/show start call and end call buttons
|
||||
mEndCallBtn->setVisible(LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
|
||||
mStartCallBtn->setVisible(LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() < LLVoiceChannel::STATE_CALL_STARTED);
|
||||
mEndCallBtn->setVisible(LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
|
||||
mStartCallBtn->setVisible(LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel->getState() < LLVoiceChannel::STATE_CALL_STARTED);
|
||||
mStartCallBtn->setEnabled(enable_connect);
|
||||
mSendBtn->setEnabled(!childGetValue("chat_editor").asString().empty());
|
||||
|
||||
@@ -1528,11 +733,11 @@ void LLFloaterIMPanel::draw()
|
||||
else
|
||||
{
|
||||
// refresh volume and mute checkbox
|
||||
mVolumeSlider->setVisible(LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive());
|
||||
mVolumeSlider->setValue(gVoiceClient->getUserVolume(mOtherParticipantUUID));
|
||||
mVolumeSlider->setVisible(LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel->isActive());
|
||||
mVolumeSlider->setValue(LLVoiceClient::getInstance()->getUserVolume(mOtherParticipantUUID));
|
||||
|
||||
mMuteBtn->setValue(LLMuteList::getInstance()->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat));
|
||||
mMuteBtn->setVisible(LLVoiceClient::voiceEnabled() && mVoiceChannel->isActive());
|
||||
mMuteBtn->setVisible(LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel->isActive());
|
||||
}
|
||||
LLFloater::draw();
|
||||
}
|
||||
@@ -1547,7 +752,8 @@ public:
|
||||
|
||||
/*virtual*/ void error(U32 statusNum, const std::string& reason)
|
||||
{
|
||||
llinfos << "Error inviting all agents to session" << llendl;
|
||||
llwarns << "Error inviting all agents to session [status:"
|
||||
<< statusNum << "]: " << reason << llendl;
|
||||
//throw something back to the viewer here?
|
||||
}
|
||||
|
||||
@@ -1992,7 +1198,7 @@ void deliver_message(const std::string& utf8_text,
|
||||
if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id)))
|
||||
{
|
||||
// User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice.
|
||||
sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text);
|
||||
sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text);
|
||||
}
|
||||
|
||||
if(!sent)
|
||||
@@ -2272,7 +1478,7 @@ void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update)
|
||||
|
||||
|
||||
//update the speakers dropdown too
|
||||
mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated);
|
||||
mSpeakerPanel->setVoiceModerationCtrlMode(session_update);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
* @brief LLIMPanel class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
@@ -47,134 +46,9 @@ class LLViewerTextEditor;
|
||||
class LLInventoryItem;
|
||||
class LLInventoryCategory;
|
||||
class LLIMSpeakerMgr;
|
||||
class LLPanelActiveSpeakers;
|
||||
class LLPanel;
|
||||
class LLParticipantList;
|
||||
class LLButton;
|
||||
|
||||
class LLVoiceChannel : public LLVoiceClientStatusObserver
|
||||
{
|
||||
public:
|
||||
typedef enum e_voice_channel_state
|
||||
{
|
||||
STATE_NO_CHANNEL_INFO,
|
||||
STATE_ERROR,
|
||||
STATE_HUNG_UP,
|
||||
STATE_READY,
|
||||
STATE_CALL_STARTED,
|
||||
STATE_RINGING,
|
||||
STATE_CONNECTED
|
||||
} EState;
|
||||
|
||||
LLVoiceChannel(const LLUUID& session_id, const std::string& session_name);
|
||||
virtual ~LLVoiceChannel();
|
||||
|
||||
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
|
||||
|
||||
virtual void handleStatusChange(EStatusType status);
|
||||
virtual void handleError(EStatusType status);
|
||||
virtual void deactivate();
|
||||
virtual void activate();
|
||||
virtual void setChannelInfo(
|
||||
const std::string& uri,
|
||||
const std::string& credentials);
|
||||
virtual void getChannelInfo();
|
||||
virtual BOOL isActive();
|
||||
virtual BOOL callStarted();
|
||||
|
||||
const LLUUID getSessionID() { return mSessionID; }
|
||||
EState getState() { return mState; }
|
||||
|
||||
void updateSessionID(const LLUUID& new_session_id);
|
||||
const LLSD& getNotifyArgs() { return mNotifyArgs; }
|
||||
|
||||
static LLVoiceChannel* getChannelByID(const LLUUID& session_id);
|
||||
static LLVoiceChannel* getChannelByURI(std::string uri);
|
||||
static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; }
|
||||
static void initClass();
|
||||
|
||||
static void suspend();
|
||||
static void resume();
|
||||
|
||||
protected:
|
||||
virtual void setState(EState state);
|
||||
void setURI(std::string uri);
|
||||
|
||||
std::string mURI;
|
||||
std::string mCredentials;
|
||||
LLUUID mSessionID;
|
||||
EState mState;
|
||||
std::string mSessionName;
|
||||
LLSD mNotifyArgs;
|
||||
BOOL mIgnoreNextSessionLeave;
|
||||
LLHandle<LLPanel> mLoginNotificationHandle;
|
||||
|
||||
typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t;
|
||||
static voice_channel_map_t sVoiceChannelMap;
|
||||
|
||||
typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t;
|
||||
static voice_channel_map_uri_t sVoiceChannelURIMap;
|
||||
|
||||
static LLVoiceChannel* sCurrentVoiceChannel;
|
||||
static LLVoiceChannel* sSuspendedVoiceChannel;
|
||||
static BOOL sSuspended;
|
||||
};
|
||||
|
||||
class LLVoiceChannelGroup : public LLVoiceChannel
|
||||
{
|
||||
public:
|
||||
LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name);
|
||||
|
||||
/*virtual*/ void handleStatusChange(EStatusType status);
|
||||
/*virtual*/ void handleError(EStatusType status);
|
||||
/*virtual*/ void activate();
|
||||
/*virtual*/ void deactivate();
|
||||
/*vritual*/ void setChannelInfo(
|
||||
const std::string& uri,
|
||||
const std::string& credentials);
|
||||
/*virtual*/ void getChannelInfo();
|
||||
|
||||
protected:
|
||||
virtual void setState(EState state);
|
||||
|
||||
private:
|
||||
U32 mRetries;
|
||||
BOOL mIsRetrying;
|
||||
};
|
||||
|
||||
class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal>
|
||||
{
|
||||
public:
|
||||
LLVoiceChannelProximal();
|
||||
|
||||
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
|
||||
/*virtual*/ void handleStatusChange(EStatusType status);
|
||||
/*virtual*/ void handleError(EStatusType status);
|
||||
/*virtual*/ BOOL isActive();
|
||||
/*virtual*/ void activate();
|
||||
/*virtual*/ void deactivate();
|
||||
|
||||
};
|
||||
|
||||
class LLVoiceChannelP2P : public LLVoiceChannelGroup
|
||||
{
|
||||
public:
|
||||
LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id);
|
||||
|
||||
/*virtual*/ void handleStatusChange(EStatusType status);
|
||||
/*virtual*/ void handleError(EStatusType status);
|
||||
/*virtual*/ void activate();
|
||||
/*virtual*/ void getChannelInfo();
|
||||
|
||||
void setSessionHandle(const std::string& handle, const std::string &inURI);
|
||||
|
||||
protected:
|
||||
virtual void setState(EState state);
|
||||
|
||||
private:
|
||||
std::string mSessionHandle;
|
||||
LLUUID mOtherUserID;
|
||||
BOOL mReceivedCall;
|
||||
};
|
||||
class LLVoiceChannel;
|
||||
|
||||
class LLFloaterIMPanel : public LLFloater
|
||||
{
|
||||
@@ -256,6 +130,7 @@ public:
|
||||
void processSessionUpdate(const LLSD& update);
|
||||
void setSpeakers(const LLSD& speaker_list);
|
||||
LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; }
|
||||
LLIMSpeakerMgr* getSpeakerManager() const { return mSpeakers; } // Singu TODO: LLIMModel::getSpeakerManager
|
||||
EInstantMessage getDialogType() const { return mDialog; }
|
||||
|
||||
void requestAutoConnect();
|
||||
@@ -368,7 +243,7 @@ private:
|
||||
BOOL mCallBackEnabled;
|
||||
|
||||
LLIMSpeakerMgr* mSpeakers;
|
||||
LLPanelActiveSpeakers* mSpeakerPanel;
|
||||
LLParticipantList* mSpeakerPanel;
|
||||
|
||||
// Optimization: Don't send "User is typing..." until the
|
||||
// user has actually been typing for a little while. Prevents
|
||||
|
||||
@@ -54,12 +54,13 @@
|
||||
#include "llhttpnode.h"
|
||||
#include "llimpanel.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llspeakers.h"
|
||||
#include "lltabcontainer.h"
|
||||
#include "llmutelist.h"
|
||||
#include "llresizehandle.h"
|
||||
#include "llviewermenu.h"
|
||||
#include "llviewermessage.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "llnotify.h"
|
||||
#include "llviewerregion.h"
|
||||
|
||||
@@ -354,10 +355,10 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
if (type == IM_SESSION_P2P_INVITE)
|
||||
{
|
||||
if(gVoiceClient)
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
std::string s = payload["session_handle"].asString();
|
||||
gVoiceClient->declineInvite(s);
|
||||
LLVoiceClient::getInstance()->declineInvite(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1551,11 +1552,17 @@ public:
|
||||
const LLSD& context,
|
||||
const LLSD& input) const
|
||||
{
|
||||
LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID());
|
||||
LLUUID session_id = input["body"]["session_id"].asUUID();
|
||||
LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id);
|
||||
if (floaterp)
|
||||
{
|
||||
floaterp->processSessionUpdate(input["body"]["info"]);
|
||||
}
|
||||
LLIMSpeakerMgr* im_mgr = floaterp ? floaterp->getSpeakerManager() : NULL; //LLIMModel::getInstance()->getSpeakerManager(session_id);
|
||||
if (im_mgr)
|
||||
{
|
||||
im_mgr->processSessionUpdate(input["body"]["info"]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1719,7 +1726,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if(!LLVoiceClient::voiceEnabled())
|
||||
if(!LLVoiceClient::getInstance()->voiceEnabled())
|
||||
{
|
||||
// Don't display voice invites unless the user has voice enabled.
|
||||
return;
|
||||
|
||||
@@ -52,22 +52,16 @@
|
||||
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "llcrc.h"
|
||||
#include "lldir.h"
|
||||
#include "lldispatcher.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llxfermanager.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llviewergenericmessage.h" // for gGenericDispatcher
|
||||
#include "llviewerwindow.h"
|
||||
#include "llworld.h" //for particle system banning
|
||||
#include "llchat.h"
|
||||
#include "llfloaterchat.h"
|
||||
#include "llimpanel.h"
|
||||
#include "llimview.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llnotifications.h"
|
||||
#include "lluistring.h"
|
||||
#include "llviewerobject.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
@@ -116,6 +110,7 @@ const char BY_NAME_SUFFIX[] = " (by name)";
|
||||
const char AGENT_SUFFIX[] = " (resident)";
|
||||
const char OBJECT_SUFFIX[] = " (object)";
|
||||
const char GROUP_SUFFIX[] = " (group)";
|
||||
const char EXTERNAL_SUFFIX[] = " (avaline)";
|
||||
|
||||
|
||||
LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags)
|
||||
@@ -160,6 +155,9 @@ std::string LLMute::getDisplayName() const
|
||||
case GROUP:
|
||||
name_with_suffix += GROUP_SUFFIX;
|
||||
break;
|
||||
case EXTERNAL:
|
||||
name_with_suffix += EXTERNAL_SUFFIX;
|
||||
break;
|
||||
}
|
||||
return name_with_suffix;
|
||||
}
|
||||
@@ -201,6 +199,14 @@ void LLMute::setFromDisplayName(const std::string& display_name)
|
||||
return;
|
||||
}
|
||||
|
||||
pos = mName.rfind(EXTERNAL_SUFFIX);
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
mName.erase(pos);
|
||||
mType = EXTERNAL;
|
||||
return;
|
||||
}
|
||||
|
||||
llwarns << "Unable to set mute from display name " << display_name << llendl;
|
||||
return;
|
||||
}
|
||||
@@ -224,39 +230,12 @@ LLMuteList* LLMuteList::getInstance()
|
||||
// LLMuteList()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMuteList::LLMuteList() :
|
||||
mIsLoaded(FALSE),
|
||||
mUserVolumesLoaded(FALSE)
|
||||
mIsLoaded(FALSE)
|
||||
{
|
||||
gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList);
|
||||
}
|
||||
|
||||
void LLMuteList::loadUserVolumes()
|
||||
{
|
||||
// call once, after LLDir::setLindenUserDir() has been called
|
||||
if (mUserVolumesLoaded)
|
||||
return;
|
||||
mUserVolumesLoaded = TRUE;
|
||||
|
||||
// load per-resident voice volume information
|
||||
// conceptually, this is part of the mute list information, although it is only stored locally
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "volume_settings.xml");
|
||||
|
||||
LLSD settings_llsd;
|
||||
llifstream file;
|
||||
file.open(filename);
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXML(settings_llsd, file);
|
||||
}
|
||||
|
||||
for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
|
||||
iter != settings_llsd.endMap(); ++iter)
|
||||
{
|
||||
mUserVolumeSettings.insert(std::make_pair(LLUUID(iter->first), (F32)iter->second.asReal()));
|
||||
}
|
||||
|
||||
LLEnvManagerNew::instance().setRegionChangeCallback(boost::bind(&LLMuteList::checkNewRegion, this));
|
||||
checkNewRegion();
|
||||
LLEnvManagerNew::instance().setRegionChangeCallback(boost::bind(&LLMuteList::checkNewRegion, this));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -264,24 +243,7 @@ void LLMuteList::loadUserVolumes()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMuteList::~LLMuteList()
|
||||
{
|
||||
// If we quit from the login screen we will not have an SL account
|
||||
// name. Don't try to save, otherwise we'll dump a file in
|
||||
// C:\Program Files\SecondLife\ JC
|
||||
std::string user_dir = gDirUtilp->getLindenUserDir(true);
|
||||
if (!user_dir.empty())
|
||||
{
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "volume_settings.xml");
|
||||
LLSD settings_llsd;
|
||||
|
||||
for(user_volume_map_t::iterator iter = mUserVolumeSettings.begin(); iter != mUserVolumeSettings.end(); ++iter)
|
||||
{
|
||||
settings_llsd[iter->first.asString()] = iter->second;
|
||||
}
|
||||
|
||||
llofstream file;
|
||||
file.open(filename);
|
||||
LLSDSerialize::toPrettyXML(settings_llsd, file);
|
||||
}
|
||||
}
|
||||
|
||||
bool LLMuteList::isLinden(const LLUUID& id) const
|
||||
@@ -333,7 +295,7 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags)
|
||||
if ((mute.mType == LLMute::AGENT)
|
||||
&& isLinden(mute.mName) && (flags & LLMute::flagTextChat || flags == 0))
|
||||
{
|
||||
LLNotificationsUtil::add("MuteLinden");
|
||||
LLNotifications::instance().add("MuteLinden", LLSD(), LLSD());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -439,6 +401,12 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags)
|
||||
|
||||
void LLMuteList::updateAdd(const LLMute& mute)
|
||||
{
|
||||
// External mutes (e.g. Avaline callers) are local only, don't send them to the server.
|
||||
if (mute.mType == LLMute::EXTERNAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the database
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
msg->newMessageFast(_PREHASH_UpdateMuteListEntry);
|
||||
@@ -526,6 +494,12 @@ BOOL LLMuteList::remove(const LLMute& mute, U32 flags)
|
||||
|
||||
void LLMuteList::updateRemove(const LLMute& mute)
|
||||
{
|
||||
// External mutes are not sent to the server anyway, no need to remove them.
|
||||
if (mute.mType == LLMute::EXTERNAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
msg->newMessageFast(_PREHASH_RemoveMuteListEntry);
|
||||
msg->nextBlockFast(_PREHASH_AgentData);
|
||||
@@ -557,7 +531,7 @@ void notify_automute_callback(const LLUUID& agent_id, const std::string& full_na
|
||||
LLSD args;
|
||||
args["NAME"] = full_name;
|
||||
|
||||
LLNotificationPtr notif_ptr = LLNotifications::instance().add(notif_name, args);
|
||||
LLNotificationPtr notif_ptr = LLNotifications::instance().add(notif_name, args, LLSD());
|
||||
if (notif_ptr)
|
||||
{
|
||||
std::string message = notif_ptr->getMessage();
|
||||
@@ -708,9 +682,14 @@ BOOL LLMuteList::saveToFile(const std::string& filename)
|
||||
it != mMutes.end();
|
||||
++it)
|
||||
{
|
||||
it->mID.toString(id_string);
|
||||
const std::string& name = it->mName;
|
||||
fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string.c_str(), name.c_str(), it->mFlags);
|
||||
// Don't save external mutes as they are not sent to the server and probably won't
|
||||
//be valid next time anyway.
|
||||
if (it->mType != LLMute::EXTERNAL)
|
||||
{
|
||||
it->mID.toString(id_string);
|
||||
const std::string& name = it->mName;
|
||||
fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string.c_str(), name.c_str(), it->mFlags);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return TRUE;
|
||||
@@ -755,8 +734,6 @@ BOOL LLMuteList::isMuted(const LLUUID& id, const std::string& name, U32 flags) c
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLMuteList::requestFromServer(const LLUUID& agent_id)
|
||||
{
|
||||
loadUserVolumes();
|
||||
|
||||
std::string agent_id_string;
|
||||
std::string filename;
|
||||
agent_id.toString(agent_id_string);
|
||||
@@ -791,26 +768,6 @@ void LLMuteList::cache(const LLUUID& agent_id)
|
||||
}
|
||||
}
|
||||
|
||||
void LLMuteList::setSavedResidentVolume(const LLUUID& id, F32 volume)
|
||||
{
|
||||
// store new value in volume settings file
|
||||
mUserVolumeSettings[id] = volume;
|
||||
}
|
||||
|
||||
F32 LLMuteList::getSavedResidentVolume(const LLUUID& id)
|
||||
{
|
||||
const F32 DEFAULT_VOLUME = 0.5f;
|
||||
|
||||
user_volume_map_t::iterator found_it = mUserVolumeSettings.find(id);
|
||||
if (found_it != mUserVolumeSettings.end())
|
||||
{
|
||||
return found_it->second;
|
||||
}
|
||||
//FIXME: assumes default, should get this from somewhere
|
||||
return DEFAULT_VOLUME;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Static message handlers
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -925,7 +882,7 @@ void LLMuteList::parseSimulatorFeatures()
|
||||
{
|
||||
LLSD godNames = info["god_names"]["last_names"];
|
||||
|
||||
for (LLSD::array_iterator godNames_it = godNames.beginArray(); godNames_it != godNames.endArray(); godNames_it++)
|
||||
for (LLSD::array_iterator godNames_it = godNames.beginArray(); godNames_it != godNames.endArray(); ++godNames_it)
|
||||
mGodLastNames.insert((*godNames_it).asString());
|
||||
}
|
||||
|
||||
@@ -933,7 +890,7 @@ void LLMuteList::parseSimulatorFeatures()
|
||||
{
|
||||
LLSD godNames = info["god_names"]["full_names"];
|
||||
|
||||
for (LLSD::array_iterator godNames_it = godNames.beginArray(); godNames_it != godNames.endArray(); godNames_it++)
|
||||
for (LLSD::array_iterator godNames_it = godNames.beginArray(); godNames_it != godNames.endArray(); ++godNames_it)
|
||||
mGodFullNames.insert((*godNames_it).asString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ class LLMute
|
||||
{
|
||||
public:
|
||||
// Legacy mutes are BY_NAME and have null UUID.
|
||||
enum EType { BY_NAME = 0, AGENT = 1, OBJECT = 2, GROUP = 3, COUNT = 4 };
|
||||
// EXTERNAL mutes are only processed through an external system (e.g. Voice) and not stored.
|
||||
enum EType { BY_NAME = 0, AGENT = 1, OBJECT = 2, GROUP = 3, EXTERNAL = 4, COUNT = 5 };
|
||||
|
||||
// Bits in the mute flags. For backwards compatibility (since any mute list entries that were created before the flags existed
|
||||
// will have a flags field of 0), some of the flags are "inverted".
|
||||
@@ -128,12 +129,7 @@ public:
|
||||
// call this method on logout to save everything.
|
||||
void cache(const LLUUID& agent_id);
|
||||
|
||||
void setSavedResidentVolume(const LLUUID& id, F32 volume);
|
||||
F32 getSavedResidentVolume(const LLUUID& id);
|
||||
|
||||
private:
|
||||
void loadUserVolumes();
|
||||
|
||||
BOOL loadFromFile(const std::string& filename);
|
||||
BOOL saveToFile(const std::string& filename);
|
||||
|
||||
@@ -183,13 +179,9 @@ private:
|
||||
observer_set_t mObservers;
|
||||
|
||||
BOOL mIsLoaded;
|
||||
BOOL mUserVolumesLoaded;
|
||||
|
||||
friend class LLDispatchEmptyMuteList;
|
||||
|
||||
typedef std::map<LLUUID, F32> user_volume_map_t;
|
||||
user_volume_map_t mUserVolumeSettings;
|
||||
|
||||
std::set<std::string> mGodLastNames;
|
||||
std::set<std::string> mGodFullNames;
|
||||
};
|
||||
|
||||
@@ -350,7 +350,7 @@ void LLOverlayBar::refresh()
|
||||
{
|
||||
// update "remotes"
|
||||
childSetVisible("media_remote_container", TRUE);
|
||||
childSetVisible("voice_remote_container", LLVoiceClient::voiceEnabled());
|
||||
childSetVisible("voice_remote_container", LLVoiceClient::getInstance()->voiceEnabled());
|
||||
childSetVisible("AdvSettings_container", !sAdvSettingsPopup);//!gSavedSettings.getBOOL("wlfAdvSettingsPopup"));
|
||||
childSetVisible("AdvSettings_container_exp", sAdvSettingsPopup);//gSavedSettings.getBOOL("wlfAdvSettingsPopup"));
|
||||
childSetVisible("ao_remote_container", gSavedSettings.getBOOL("EnableAORemote"));
|
||||
@@ -358,7 +358,7 @@ void LLOverlayBar::refresh()
|
||||
}
|
||||
}
|
||||
if(!in_mouselook)
|
||||
mVoiceRemoteContainer->setVisible(LLVoiceClient::voiceEnabled());
|
||||
mVoiceRemoteContainer->setVisible(LLVoiceClient::getInstance()->voiceEnabled());
|
||||
|
||||
// always let user toggle into and out of chatbar
|
||||
static const LLCachedControl<bool> chat_visible("ChatVisible",true);
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "llpanel.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
struct LLOfferInfo;
|
||||
class LLOfferInfo;
|
||||
|
||||
const F32 UPDATE_MEMBERS_SECONDS_PER_FRAME = 0.005; // 5ms
|
||||
|
||||
|
||||
328
indra/newview/llpanelvoicedevicesettings.cpp
Normal file
328
indra/newview/llpanelvoicedevicesettings.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
/**
|
||||
* @file llpanelvoicedevicesettings.cpp
|
||||
* @author Richard Nelson
|
||||
* @brief Voice communication set-up
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llpanelvoicedevicesettings.h"
|
||||
|
||||
// Viewer includes
|
||||
#include "llcombobox.h"
|
||||
#include "llsliderctrl.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llvoiceclient.h"
|
||||
#include "llvoicechannel.h"
|
||||
|
||||
// Library includes (after viewer)
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
|
||||
static const std::string DEFAULT_DEVICE("Default");
|
||||
|
||||
|
||||
LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings()
|
||||
: LLPanel()
|
||||
{
|
||||
mCtrlInputDevices = NULL;
|
||||
mCtrlOutputDevices = NULL;
|
||||
mInputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
|
||||
mOutputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
|
||||
mDevicesUpdated = FALSE;
|
||||
mUseTuningMode = true;
|
||||
|
||||
// grab "live" mic volume level
|
||||
mMicVolume = gSavedSettings.getF32("AudioLevelMic");
|
||||
|
||||
}
|
||||
|
||||
LLPanelVoiceDeviceSettings::~LLPanelVoiceDeviceSettings()
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLPanelVoiceDeviceSettings::postBuild()
|
||||
{
|
||||
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
|
||||
// set mic volume tuning slider based on last mic volume setting
|
||||
volume_slider->setValue(mMicVolume);
|
||||
|
||||
mCtrlInputDevices = getChild<LLComboBox>("voice_input_device");
|
||||
mCtrlOutputDevices = getChild<LLComboBox>("voice_output_device");
|
||||
|
||||
mCtrlInputDevices->setCommitCallback(
|
||||
boost::bind(&LLPanelVoiceDeviceSettings::onCommitInputDevice, this));
|
||||
mCtrlOutputDevices->setCommitCallback(
|
||||
boost::bind(&LLPanelVoiceDeviceSettings::onCommitOutputDevice, this));
|
||||
|
||||
mLocalizedDeviceNames[DEFAULT_DEVICE] = getString("default_text");
|
||||
mLocalizedDeviceNames["No Device"] = getString("name_no_device");
|
||||
mLocalizedDeviceNames["Default System Device"] = getString("name_default_system_device");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLPanelVoiceDeviceSettings::handleVisibilityChange ( BOOL new_visibility )
|
||||
{
|
||||
if (new_visibility)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanup();
|
||||
// when closing this window, turn off visiblity control so that
|
||||
// next time preferences is opened we don't suspend voice
|
||||
gSavedSettings.setBOOL("ShowDeviceSettings", FALSE);
|
||||
}
|
||||
}
|
||||
void LLPanelVoiceDeviceSettings::draw()
|
||||
{
|
||||
refresh();
|
||||
|
||||
// let user know that volume indicator is not yet available
|
||||
bool is_in_tuning_mode = LLVoiceClient::getInstance()->inTuningMode();
|
||||
getChildView("wait_text")->setVisible( !is_in_tuning_mode && mUseTuningMode);
|
||||
|
||||
LLPanel::draw();
|
||||
|
||||
if (is_in_tuning_mode)
|
||||
{
|
||||
const S32 num_bars = 5;
|
||||
F32 voice_power = LLVoiceClient::getInstance()->tuningGetEnergy() / LLVoiceClient::OVERDRIVEN_POWER_LEVEL;
|
||||
S32 discrete_power = llmin(num_bars, llfloor(voice_power * (F32)num_bars + 0.1f));
|
||||
|
||||
for(S32 power_bar_idx = 0; power_bar_idx < num_bars; power_bar_idx++)
|
||||
{
|
||||
std::string view_name = llformat("%s%d", "bar", power_bar_idx);
|
||||
LLView* bar_view = getChild<LLView>(view_name);
|
||||
if (bar_view)
|
||||
{
|
||||
gl_rect_2d(bar_view->getRect(), LLColor4::grey, TRUE);
|
||||
|
||||
LLColor4 color;
|
||||
if (power_bar_idx < discrete_power)
|
||||
{
|
||||
color = (power_bar_idx >= 3) ? gSavedSettings.getColor4("OverdrivenColor") : gSavedSettings.getColor4("SpeakingColor");
|
||||
}
|
||||
else
|
||||
{
|
||||
color = LLUI::sColorsGroup->getColor("FocusBackgroundColor");
|
||||
}
|
||||
|
||||
LLRect color_rect = bar_view->getRect();
|
||||
color_rect.stretch(-1);
|
||||
gl_rect_2d(color_rect, color, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::apply()
|
||||
{
|
||||
std::string s;
|
||||
if(mCtrlInputDevices)
|
||||
{
|
||||
s = mCtrlInputDevices->getValue().asString();
|
||||
gSavedSettings.setString("VoiceInputAudioDevice", s);
|
||||
mInputDevice = s;
|
||||
}
|
||||
|
||||
if(mCtrlOutputDevices)
|
||||
{
|
||||
s = mCtrlOutputDevices->getValue().asString();
|
||||
gSavedSettings.setString("VoiceOutputAudioDevice", s);
|
||||
mOutputDevice = s;
|
||||
}
|
||||
|
||||
// assume we are being destroyed by closing our embedding window
|
||||
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
|
||||
if(volume_slider)
|
||||
{
|
||||
F32 slider_value = (F32)volume_slider->getValue().asReal();
|
||||
gSavedSettings.setF32("AudioLevelMic", slider_value);
|
||||
mMicVolume = slider_value;
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::cancel()
|
||||
{
|
||||
gSavedSettings.setString("VoiceInputAudioDevice", mInputDevice);
|
||||
gSavedSettings.setString("VoiceOutputAudioDevice", mOutputDevice);
|
||||
|
||||
if(mCtrlInputDevices)
|
||||
mCtrlInputDevices->setValue(mInputDevice);
|
||||
|
||||
if(mCtrlOutputDevices)
|
||||
mCtrlOutputDevices->setValue(mOutputDevice);
|
||||
|
||||
gSavedSettings.setF32("AudioLevelMic", mMicVolume);
|
||||
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
|
||||
if(volume_slider)
|
||||
{
|
||||
volume_slider->setValue(mMicVolume);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::refresh()
|
||||
{
|
||||
//grab current volume
|
||||
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
|
||||
// set mic volume tuning slider based on last mic volume setting
|
||||
F32 current_volume = (F32)volume_slider->getValue().asReal();
|
||||
LLVoiceClient::getInstance()->tuningSetMicVolume(current_volume);
|
||||
|
||||
// Fill in popup menus
|
||||
bool device_settings_available = LLVoiceClient::getInstance()->deviceSettingsAvailable();
|
||||
|
||||
if (mCtrlInputDevices)
|
||||
{
|
||||
mCtrlInputDevices->setEnabled(device_settings_available);
|
||||
}
|
||||
|
||||
if (mCtrlOutputDevices)
|
||||
{
|
||||
mCtrlOutputDevices->setEnabled(device_settings_available);
|
||||
}
|
||||
|
||||
getChild<LLSlider>("mic_volume_slider")->setEnabled(device_settings_available);
|
||||
|
||||
if(!device_settings_available)
|
||||
{
|
||||
// The combo boxes are disabled, since we can't get the device settings from the daemon just now.
|
||||
// Put the currently set default (ONLY) in the box, and select it.
|
||||
if(mCtrlInputDevices)
|
||||
{
|
||||
mCtrlInputDevices->removeall();
|
||||
mCtrlInputDevices->add(getLocalizedDeviceName(mInputDevice), mInputDevice, ADD_BOTTOM);
|
||||
mCtrlInputDevices->setValue(mInputDevice);
|
||||
}
|
||||
if(mCtrlOutputDevices)
|
||||
{
|
||||
mCtrlOutputDevices->removeall();
|
||||
mCtrlOutputDevices->add(getLocalizedDeviceName(mOutputDevice), mOutputDevice, ADD_BOTTOM);
|
||||
mCtrlOutputDevices->setValue(mOutputDevice);
|
||||
}
|
||||
mDevicesUpdated = FALSE;
|
||||
}
|
||||
else if (!mDevicesUpdated)
|
||||
{
|
||||
LLVoiceDeviceList::const_iterator iter;
|
||||
|
||||
if(mCtrlInputDevices)
|
||||
{
|
||||
mCtrlInputDevices->removeall();
|
||||
mCtrlInputDevices->add(getLocalizedDeviceName(DEFAULT_DEVICE), DEFAULT_DEVICE, ADD_BOTTOM);
|
||||
|
||||
for(iter=LLVoiceClient::getInstance()->getCaptureDevices().begin();
|
||||
iter != LLVoiceClient::getInstance()->getCaptureDevices().end();
|
||||
iter++)
|
||||
{
|
||||
mCtrlInputDevices->add(getLocalizedDeviceName(*iter), *iter, ADD_BOTTOM);
|
||||
}
|
||||
|
||||
// Fix invalid input audio device preference.
|
||||
if (!mCtrlInputDevices->setSelectedByValue(mInputDevice, TRUE))
|
||||
{
|
||||
mCtrlInputDevices->setValue(DEFAULT_DEVICE);
|
||||
gSavedSettings.setString("VoiceInputAudioDevice", DEFAULT_DEVICE);
|
||||
mInputDevice = DEFAULT_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
if(mCtrlOutputDevices)
|
||||
{
|
||||
mCtrlOutputDevices->removeall();
|
||||
mCtrlOutputDevices->add(getLocalizedDeviceName(DEFAULT_DEVICE), DEFAULT_DEVICE, ADD_BOTTOM);
|
||||
|
||||
for(iter= LLVoiceClient::getInstance()->getRenderDevices().begin();
|
||||
iter != LLVoiceClient::getInstance()->getRenderDevices().end(); iter++)
|
||||
{
|
||||
mCtrlOutputDevices->add(getLocalizedDeviceName(*iter), *iter, ADD_BOTTOM);
|
||||
}
|
||||
|
||||
// Fix invalid output audio device preference.
|
||||
if (!mCtrlOutputDevices->setSelectedByValue(mOutputDevice, TRUE))
|
||||
{
|
||||
mCtrlOutputDevices->setValue(DEFAULT_DEVICE);
|
||||
gSavedSettings.setString("VoiceOutputAudioDevice", DEFAULT_DEVICE);
|
||||
mOutputDevice = DEFAULT_DEVICE;
|
||||
}
|
||||
}
|
||||
mDevicesUpdated = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::initialize()
|
||||
{
|
||||
mInputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
|
||||
mOutputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
|
||||
mMicVolume = gSavedSettings.getF32("AudioLevelMic");
|
||||
mDevicesUpdated = FALSE;
|
||||
|
||||
// ask for new device enumeration
|
||||
LLVoiceClient::getInstance()->refreshDeviceLists();
|
||||
|
||||
// put voice client in "tuning" mode
|
||||
if (mUseTuningMode)
|
||||
{
|
||||
LLVoiceClient::getInstance()->tuningStart();
|
||||
LLVoiceChannel::suspend();
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::cleanup()
|
||||
{
|
||||
if (mUseTuningMode)
|
||||
{
|
||||
LLVoiceClient::getInstance()->tuningStop();
|
||||
LLVoiceChannel::resume();
|
||||
}
|
||||
}
|
||||
|
||||
// returns English name if no translation found
|
||||
std::string LLPanelVoiceDeviceSettings::getLocalizedDeviceName(const std::string& en_dev_name)
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator it = mLocalizedDeviceNames.find(en_dev_name);
|
||||
return it != mLocalizedDeviceNames.end() ? it->second : en_dev_name;
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::onCommitInputDevice()
|
||||
{
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceClient::getInstance()->setCaptureDevice(
|
||||
mCtrlInputDevices->getValue().asString());
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelVoiceDeviceSettings::onCommitOutputDevice()
|
||||
{
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceClient::getInstance()->setRenderDevice(
|
||||
mCtrlInputDevices->getValue().asString());
|
||||
}
|
||||
}
|
||||
67
indra/newview/llpanelvoicedevicesettings.h
Normal file
67
indra/newview/llpanelvoicedevicesettings.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @file llpanelvoicedevicesettings.h
|
||||
* @author Richard Nelson
|
||||
* @brief Voice communication set-up wizard
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLPANELVOICEDEVICESETTINGS_H
|
||||
#define LL_LLPANELVOICEDEVICESETTINGS_H
|
||||
|
||||
#include "llpanel.h"
|
||||
|
||||
class LLPanelVoiceDeviceSettings : public LLPanel
|
||||
{
|
||||
public:
|
||||
LLPanelVoiceDeviceSettings();
|
||||
~LLPanelVoiceDeviceSettings();
|
||||
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ BOOL postBuild();
|
||||
void apply();
|
||||
void cancel();
|
||||
void refresh();
|
||||
void initialize();
|
||||
void cleanup();
|
||||
|
||||
/*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
|
||||
|
||||
void setUseTuningMode(bool use) { mUseTuningMode = use; };
|
||||
|
||||
protected:
|
||||
std::string getLocalizedDeviceName(const std::string& en_dev_name);
|
||||
|
||||
void onCommitInputDevice();
|
||||
void onCommitOutputDevice();
|
||||
|
||||
F32 mMicVolume;
|
||||
std::string mInputDevice;
|
||||
std::string mOutputDevice;
|
||||
class LLComboBox *mCtrlInputDevices;
|
||||
class LLComboBox *mCtrlOutputDevices;
|
||||
BOOL mDevicesUpdated;
|
||||
bool mUseTuningMode;
|
||||
std::map<std::string, std::string> mLocalizedDeviceNames;
|
||||
};
|
||||
|
||||
#endif // LL_LLPANELVOICEDEVICESETTINGS_H
|
||||
597
indra/newview/llparticipantlist.cpp
Normal file
597
indra/newview/llparticipantlist.cpp
Normal file
@@ -0,0 +1,597 @@
|
||||
/**
|
||||
* @file llparticipantlist.cpp
|
||||
* @brief LLParticipantList intended to update view(LLAvatarList) according to incoming messages
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llavataractions.h"
|
||||
#include "llagent.h"
|
||||
#include "llmutelist.h"
|
||||
#include "llparticipantlist.h"
|
||||
#include "llscrolllistctrl.h"
|
||||
#include "llspeakers.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llvoiceclient.h"
|
||||
#include "llworld.h" // Edit: For ghost detection
|
||||
// [RLVa:KB]
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
|
||||
LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source,
|
||||
bool show_text_chatters) :
|
||||
mSpeakerMgr(data_source),
|
||||
mAvatarList(NULL),
|
||||
mShowTextChatters(show_text_chatters),
|
||||
mValidateSpeakerCallback(NULL)
|
||||
{
|
||||
setMouseOpaque(false);
|
||||
|
||||
/* Singu TODO: Avaline?
|
||||
mAvalineUpdater = new LLAvalineUpdater(boost::bind(&LLParticipantList::onAvalineCallerFound, this, _1),
|
||||
boost::bind(&LLParticipantList::onAvalineCallerRemoved, this, _1));*/
|
||||
|
||||
mSpeakerAddListener = new SpeakerAddListener(*this);
|
||||
mSpeakerRemoveListener = new SpeakerRemoveListener(*this);
|
||||
mSpeakerClearListener = new SpeakerClearListener(*this);
|
||||
//mSpeakerModeratorListener = new SpeakerModeratorUpdateListener(*this);
|
||||
mSpeakerMuteListener = new SpeakerMuteListener(*this);
|
||||
|
||||
mSpeakerMgr->addListener(mSpeakerAddListener, "add");
|
||||
mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove");
|
||||
mSpeakerMgr->addListener(mSpeakerClearListener, "clear");
|
||||
//mSpeakerMgr->addListener(mSpeakerModeratorListener, "update_moderator");
|
||||
}
|
||||
|
||||
BOOL LLParticipantList::postBuild()
|
||||
{
|
||||
mAvatarList = getChild<LLScrollListCtrl>("speakers_list");
|
||||
|
||||
mAvatarList->sortByColumn(gSavedSettings.getString("FloaterActiveSpeakersSortColumn"), gSavedSettings.getBOOL("FloaterActiveSpeakersSortAscending"));
|
||||
mAvatarList->setDoubleClickCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this));
|
||||
mAvatarList->setCommitOnSelectionChange(true);
|
||||
mAvatarList->setCommitCallback(boost::bind(&LLParticipantList::handleSpeakerSelect, this));
|
||||
mAvatarList->setSortChangedCallback(boost::bind(&LLParticipantList::onSortChanged, this));
|
||||
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("mute_text_btn"))
|
||||
ctrl->setCommitCallback(boost::bind(&LLParticipantList::toggleMuteText, this));
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("mute_btn"))
|
||||
ctrl->setCommitCallback(boost::bind(&LLParticipantList::toggleMuteVoice, this));
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("speaker_volume"))
|
||||
ctrl->setCommitCallback(boost::bind(&LLParticipantList::onVolumeChange, this, _2));
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("profile_btn"))
|
||||
ctrl->setCommitCallback(boost::bind(&LLParticipantList::onClickProfile, this));
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("moderator_allow_voice"))
|
||||
ctrl->setCommitCallback(boost::bind(&LLParticipantList::moderateVoiceParticipant, this, _2));
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("moderator_allow_text"))
|
||||
ctrl->setCommitCallback(boost::bind(&LLParticipantList::toggleAllowTextChat, this, _2));
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("moderator_mode"))
|
||||
ctrl->setCommitCallback(boost::bind(&LLParticipantList::moderateVoiceAllParticipants, this, _2));
|
||||
|
||||
// update speaker UI
|
||||
handleSpeakerSelect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LLParticipantList::~LLParticipantList()
|
||||
{
|
||||
/* Singu TODO?
|
||||
mAvatarListDoubleClickConnection.disconnect();
|
||||
mAvatarListRefreshConnection.disconnect();
|
||||
mAvatarListReturnConnection.disconnect();
|
||||
mAvatarListToggleIconsConnection.disconnect();
|
||||
|
||||
// It is possible Participant List will be re-created from LLCallFloater::onCurrentChannelChanged()
|
||||
// See ticket EXT-3427
|
||||
// hide menu before deleting it to stop enable and check handlers from triggering.
|
||||
if(mParticipantListMenu && !LLApp::isExiting())
|
||||
{
|
||||
mParticipantListMenu->hide();
|
||||
}
|
||||
|
||||
if (mParticipantListMenu)
|
||||
{
|
||||
delete mParticipantListMenu;
|
||||
mParticipantListMenu = NULL;
|
||||
}
|
||||
|
||||
mAvatarList->setContextMenu(NULL);
|
||||
mAvatarList->setComparator(NULL);
|
||||
|
||||
delete mAvalineUpdater;
|
||||
*/
|
||||
}
|
||||
|
||||
/*void LLParticipantList::setSpeakingIndicatorsVisible(BOOL visible)
|
||||
{
|
||||
mAvatarList->setSpeakingIndicatorsVisible(visible);
|
||||
}*/
|
||||
|
||||
|
||||
void LLParticipantList::onAvatarListDoubleClicked()
|
||||
{
|
||||
LLAvatarActions::startIM(mAvatarList->getValue().asUUID());
|
||||
}
|
||||
|
||||
void LLParticipantList::handleSpeakerSelect()
|
||||
{
|
||||
const LLUUID& speaker_id = mAvatarList->getValue().asUUID();
|
||||
LLPointer<LLSpeaker> selected_speakerp = mSpeakerMgr->findSpeaker(speaker_id);
|
||||
if (speaker_id.isNull() || selected_speakerp.isNull())
|
||||
{
|
||||
// Disable normal controls
|
||||
if (LLView* view = findChild<LLView>("mute_btn"))
|
||||
view->setEnabled(false);
|
||||
if (LLView* view = findChild<LLView>("mute_text_btn"))
|
||||
view->setEnabled(false);
|
||||
if (LLView* view = findChild<LLView>("speaker_volume"))
|
||||
view->setEnabled(false);
|
||||
// Hide moderator controls
|
||||
if (LLView* view = findChild<LLView>("moderation_mode_panel"))
|
||||
view->setVisible(false);
|
||||
if (LLView* view = findChild<LLView>("moderator_controls"))
|
||||
view->setVisible(false);
|
||||
// Clear the name
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("resident_name"))
|
||||
ctrl->setValue(LLStringUtil::null);
|
||||
return;
|
||||
}
|
||||
|
||||
mSpeakerMuteListener->clearDispatchers();
|
||||
|
||||
bool valid_speaker = selected_speakerp->mType == LLSpeaker::SPEAKER_AGENT || selected_speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL;
|
||||
bool can_mute = valid_speaker && LLAvatarActions::canBlock(speaker_id);
|
||||
bool voice_enabled = valid_speaker && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id);
|
||||
// since setting these values is delayed by a round trip to the Vivox servers
|
||||
// update them only when selecting a new speaker or
|
||||
// asynchronously when an update arrives
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("moderator_allow_voice"))
|
||||
{
|
||||
ctrl->setEnabled(voice_enabled);
|
||||
ctrl->setValue(!selected_speakerp->mModeratorMutedVoice);
|
||||
}
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("moderator_allow_text"))
|
||||
{
|
||||
ctrl->setEnabled(true);
|
||||
ctrl->setValue(!selected_speakerp->mModeratorMutedText);
|
||||
}
|
||||
if (LLView* view = findChild<LLView>("moderator_controls_label"))
|
||||
{
|
||||
view->setEnabled(true);
|
||||
}
|
||||
// update UI for selected participant
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("mute_btn"))
|
||||
{
|
||||
ctrl->setValue(LLAvatarActions::isVoiceMuted(speaker_id));
|
||||
ctrl->setEnabled(can_mute && voice_enabled);
|
||||
}
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("mute_text_btn"))
|
||||
{
|
||||
ctrl->setValue(LLAvatarActions::isBlocked(speaker_id));
|
||||
ctrl->setEnabled(can_mute);
|
||||
}
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("speaker_volume"))
|
||||
{
|
||||
// Singu Note: Allow modifying own voice volume during a voice session (Which is valued at half of what it should be)
|
||||
ctrl->setValue(gAgentID == speaker_id ? gSavedSettings.getF32("AudioLevelMic")/2 : LLVoiceClient::getInstance()->getUserVolume(speaker_id));
|
||||
ctrl->setEnabled(valid_speaker && voice_enabled);
|
||||
}
|
||||
if (LLView* view = findChild<LLView>("profile_btn"))
|
||||
{
|
||||
view->setEnabled(selected_speakerp->mType != LLSpeaker::SPEAKER_EXTERNAL);
|
||||
}
|
||||
// show selected user name in large font
|
||||
if (LLUICtrl* ctrl = findChild<LLUICtrl>("resident_name"))
|
||||
{
|
||||
ctrl->setValue(selected_speakerp->mDisplayName);
|
||||
}
|
||||
selected_speakerp->addListener(mSpeakerMuteListener);
|
||||
|
||||
//update moderator capabilities
|
||||
LLPointer<LLSpeaker> self_speakerp = mSpeakerMgr->findSpeaker(gAgentID);
|
||||
if (self_speakerp.isNull()) return;
|
||||
|
||||
if (LLView* view = findChild<LLView>("moderation_mode_panel"))
|
||||
{
|
||||
view->setVisible(self_speakerp->mIsModerator && mSpeakerMgr->isVoiceActive());
|
||||
}
|
||||
if (LLView* view = findChild<LLView>("moderator_controls"))
|
||||
{
|
||||
view->setVisible(self_speakerp->mIsModerator);
|
||||
}
|
||||
}
|
||||
|
||||
void LLParticipantList::refreshSpeakers()
|
||||
{
|
||||
// store off current selection and scroll state to preserve across list rebuilds
|
||||
const S32 scroll_pos = mAvatarList->getScrollInterface()->getScrollPos();
|
||||
|
||||
// decide whether it's ok to resort the list then update the speaker manager appropriately.
|
||||
// rapid resorting by activity makes it hard to interact with speakers in the list
|
||||
// so we freeze the sorting while the user appears to be interacting with the control.
|
||||
// we assume this is the case whenever the mouse pointer is within the active speaker
|
||||
// panel and hasn't been motionless for more than a few seconds. see DEV-6655 -MG
|
||||
LLRect screen_rect;
|
||||
localRectToScreen(getLocalRect(), &screen_rect);
|
||||
mSpeakerMgr->update(!(screen_rect.pointInRect(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY()) && gMouseIdleTimer.getElapsedTimeF32() < 5.f));
|
||||
|
||||
std::vector<LLScrollListItem*> items = mAvatarList->getAllData();
|
||||
for (std::vector<LLScrollListItem*>::iterator item_it = items.begin(); item_it != items.end(); ++item_it)
|
||||
{
|
||||
LLScrollListItem* itemp = (*item_it);
|
||||
LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(itemp->getUUID());
|
||||
if (speakerp.isNull()) continue;
|
||||
|
||||
if (LLScrollListCell* icon_cell = itemp->getColumn(0))
|
||||
{
|
||||
if (speakerp->mStatus == LLSpeaker::STATUS_MUTED)
|
||||
{
|
||||
icon_cell->setValue("mute_icon.tga");
|
||||
static const LLCachedControl<LLColor4> sAscentMutedColor(gColors, "AscentMutedColor");
|
||||
icon_cell->setColor(speakerp->mModeratorMutedVoice ? /*LLColor4::grey*/sAscentMutedColor : LLColor4(1.f, 71.f / 255.f, 71.f / 255.f, 1.f));
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(llmin(2, llfloor((speakerp->mSpeechVolume / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f)))
|
||||
{
|
||||
case 0:
|
||||
icon_cell->setValue("icn_active-speakers-dot-lvl0.tga");
|
||||
break;
|
||||
case 1:
|
||||
icon_cell->setValue("icn_active-speakers-dot-lvl1.tga");
|
||||
break;
|
||||
case 2:
|
||||
icon_cell->setValue("icn_active-speakers-dot-lvl2.tga");
|
||||
break;
|
||||
}
|
||||
// non voice speakers have hidden icons, render as transparent
|
||||
icon_cell->setColor(speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE ? LLColor4::transparent : speakerp->mDotColor);
|
||||
}
|
||||
}
|
||||
// update name column
|
||||
if (LLScrollListCell* name_cell = itemp->getColumn(1))
|
||||
{
|
||||
if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL)
|
||||
{
|
||||
// draw inactive speakers in different color
|
||||
static const LLCachedControl<LLColor4> sSpeakersInactive(gColors, "SpeakersInactive");
|
||||
name_cell->setColor(sSpeakersInactive);
|
||||
}
|
||||
else
|
||||
{
|
||||
// <edit>
|
||||
bool found = mShowTextChatters || speakerp->mID == gAgentID;
|
||||
const LLWorld::region_list_t& regions = LLWorld::getInstance()->getRegionList();
|
||||
for (LLWorld::region_list_t::const_iterator iter = regions.begin(); !found && iter != regions.end(); ++iter)
|
||||
{
|
||||
// Are they in this sim?
|
||||
if (const LLViewerRegion* regionp = *iter)
|
||||
if (regionp->mMapAvatarIDs.find(speakerp->mID) != -1)
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
static const LLCachedControl<LLColor4> sSpeakersGhost(gColors, "SpeakersGhost");
|
||||
name_cell->setColor(sSpeakersGhost);
|
||||
}
|
||||
else
|
||||
// </edit>
|
||||
{
|
||||
static const LLCachedControl<LLColor4> sDefaultListText(gColors, "DefaultListText");
|
||||
name_cell->setColor(sDefaultListText);
|
||||
}
|
||||
}
|
||||
|
||||
std::string speaker_name = speakerp->mDisplayName.empty() ? LLCacheName::getDefaultName() : speakerp->mDisplayName;
|
||||
if (speakerp->mIsModerator)
|
||||
speaker_name += " " + getString("moderator_label");
|
||||
name_cell->setValue(speaker_name);
|
||||
static_cast<LLScrollListText*>(name_cell)->setFontStyle(speakerp->mIsModerator ? LLFontGL::BOLD : LLFontGL::NORMAL);
|
||||
}
|
||||
// update speaking order column
|
||||
if (LLScrollListCell* speaking_status_cell = itemp->getColumn(2))
|
||||
{
|
||||
// since we are forced to sort by text, encode sort order as string
|
||||
// print speaking ordinal in a text-sorting friendly manner
|
||||
speaking_status_cell->setValue(llformat("%010d", speakerp->mSortIndex));
|
||||
}
|
||||
}
|
||||
|
||||
// we potentially modified the sort order by touching the list items
|
||||
mAvatarList->setNeedsSort();
|
||||
|
||||
// keep scroll value stable
|
||||
mAvatarList->getScrollInterface()->setScrollPos(scroll_pos);
|
||||
}
|
||||
|
||||
void LLParticipantList::setValidateSpeakerCallback(validate_speaker_callback_t cb)
|
||||
{
|
||||
mValidateSpeakerCallback = cb;
|
||||
}
|
||||
|
||||
bool LLParticipantList::onAddItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
|
||||
{
|
||||
LLUUID uu_id = event->getValue().asUUID();
|
||||
|
||||
if (mValidateSpeakerCallback && !mValidateSpeakerCallback(uu_id))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
addAvatarIDExceptAgent(uu_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParticipantList::onRemoveItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
|
||||
{
|
||||
const S32 pos = mAvatarList->getItemIndex(event->getValue().asUUID());
|
||||
if (pos != -1)
|
||||
{
|
||||
mAvatarList->deleteSingleItem(pos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParticipantList::onClearListEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
|
||||
{
|
||||
mAvatarList->clearRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParticipantList::onSpeakerMuteEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = (LLSpeaker*)event->getSource();
|
||||
if (speakerp.isNull()) return false;
|
||||
|
||||
// update UI on confirmation of moderator mutes
|
||||
if (event->getValue().asString() == "voice")
|
||||
{
|
||||
childSetValue("moderator_allow_voice", !speakerp->mModeratorMutedVoice);
|
||||
}
|
||||
else if (event->getValue().asString() == "text")
|
||||
{
|
||||
childSetValue("moderator_allow_text", !speakerp->mModeratorMutedText);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id)
|
||||
{
|
||||
//if (mExcludeAgent && gAgent.getID() == avatar_id) return;
|
||||
if (mAvatarList->getItemIndex(avatar_id) != -1) return;
|
||||
|
||||
/* Singu TODO: Avaline?
|
||||
bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(avatar_id);
|
||||
|
||||
if (is_avatar)
|
||||
{
|
||||
mAvatarList->getIDs().push_back(avatar_id);
|
||||
mAvatarList->setDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string display_name = LLVoiceClient::getInstance()->getDisplayName(avatar_id);
|
||||
mAvatarList->addAvalineItem(avatar_id, mSpeakerMgr->getSessionID(), display_name.empty() ? LLTrans::getString("AvatarNameWaiting") : display_name);
|
||||
mAvalineUpdater->watchAvalineCaller(avatar_id);
|
||||
}*/
|
||||
adjustParticipant(avatar_id);
|
||||
}
|
||||
|
||||
void LLParticipantList::adjustParticipant(const LLUUID& speaker_id)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id);
|
||||
if (speakerp.isNull()) return;
|
||||
|
||||
LLSD row;
|
||||
row["id"] = speaker_id;
|
||||
LLSD& columns = row["columns"];
|
||||
columns[0]["column"] = "icon_speaking_status";
|
||||
columns[0]["type"] = "icon";
|
||||
columns[0]["value"] = "icn_active-speakers-dot-lvl0.tga";
|
||||
|
||||
const std::string& display_name = LLVoiceClient::getInstance()->getDisplayName(speaker_id);
|
||||
columns[1]["column"] = "speaker_name";
|
||||
columns[1]["type"] = "text";
|
||||
columns[1]["value"] = display_name.empty() ? LLCacheName::getDefaultName() : display_name;
|
||||
|
||||
columns[2]["column"] = "speaking_status";
|
||||
columns[2]["type"] = "text";
|
||||
columns[2]["value"] = llformat("%010d", speakerp->mSortIndex); // print speaking ordinal in a text-sorting friendly manner
|
||||
mAvatarList->addElement(row);
|
||||
|
||||
// add listener to process moderation changes
|
||||
speakerp->addListener(mSpeakerMuteListener);
|
||||
}
|
||||
|
||||
//
|
||||
// LLParticipantList::SpeakerAddListener
|
||||
//
|
||||
bool LLParticipantList::SpeakerAddListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
|
||||
{
|
||||
/**
|
||||
* We need to filter speaking objects. These objects shouldn't appear in the list
|
||||
* @see LLFloaterChat::addChat() in llviewermessage.cpp to get detailed call hierarchy
|
||||
*/
|
||||
const LLUUID& speaker_id = event->getValue().asUUID();
|
||||
LLPointer<LLSpeaker> speaker = mParent.mSpeakerMgr->findSpeaker(speaker_id);
|
||||
if(speaker.isNull() || speaker->mType == LLSpeaker::SPEAKER_OBJECT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return mParent.onAddItemEvent(event, userdata);
|
||||
}
|
||||
|
||||
//
|
||||
// LLParticipantList::SpeakerRemoveListener
|
||||
//
|
||||
bool LLParticipantList::SpeakerRemoveListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
|
||||
{
|
||||
return mParent.onRemoveItemEvent(event, userdata);
|
||||
}
|
||||
|
||||
//
|
||||
// LLParticipantList::SpeakerClearListener
|
||||
//
|
||||
bool LLParticipantList::SpeakerClearListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
|
||||
{
|
||||
return mParent.onClearListEvent(event, userdata);
|
||||
}
|
||||
|
||||
//
|
||||
// LLParticipantList::SpeakerMuteListener
|
||||
//
|
||||
bool LLParticipantList::SpeakerMuteListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
|
||||
{
|
||||
return mParent.onSpeakerMuteEvent(event, userdata);
|
||||
}
|
||||
|
||||
// Singu Note: The following functions are actually of the LLParticipantListMenu class, but we haven't married lists with menus yet.
|
||||
void LLParticipantList::toggleAllowTextChat(const LLSD& userdata)
|
||||
{
|
||||
if (!gAgent.getRegion()) return;
|
||||
LLIMSpeakerMgr* mgr = dynamic_cast<LLIMSpeakerMgr*>(mSpeakerMgr);
|
||||
if (mgr)
|
||||
{
|
||||
const LLUUID speaker_id = mAvatarList->getValue();
|
||||
mgr->toggleAllowTextChat(speaker_id);
|
||||
}
|
||||
}
|
||||
|
||||
void LLParticipantList::toggleMute(const LLSD& userdata, U32 flags)
|
||||
{
|
||||
const LLUUID speaker_id = userdata.asUUID(); //mUUIDs.front();
|
||||
BOOL is_muted = LLMuteList::getInstance()->isMuted(speaker_id, flags);
|
||||
std::string name;
|
||||
|
||||
//fill in name using voice client's copy of name cache
|
||||
LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id);
|
||||
if (speakerp.isNull())
|
||||
{
|
||||
LL_WARNS("Speakers") << "Speaker " << speaker_id << " not found" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
name = speakerp->mDisplayName;
|
||||
|
||||
LLMute::EType mute_type;
|
||||
switch (speakerp->mType)
|
||||
{
|
||||
case LLSpeaker::SPEAKER_AGENT:
|
||||
mute_type = LLMute::AGENT;
|
||||
break;
|
||||
case LLSpeaker::SPEAKER_OBJECT:
|
||||
mute_type = LLMute::OBJECT;
|
||||
break;
|
||||
case LLSpeaker::SPEAKER_EXTERNAL:
|
||||
default:
|
||||
mute_type = LLMute::EXTERNAL;
|
||||
break;
|
||||
}
|
||||
LLMute mute(speaker_id, name, mute_type);
|
||||
|
||||
if (!is_muted)
|
||||
{
|
||||
LLMuteList::getInstance()->add(mute, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLMuteList::getInstance()->remove(mute, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void LLParticipantList::toggleMuteText()
|
||||
{
|
||||
toggleMute(mAvatarList->getValue(), LLMute::flagTextChat);
|
||||
}
|
||||
|
||||
void LLParticipantList::toggleMuteVoice()
|
||||
{
|
||||
toggleMute(mAvatarList->getValue(), LLMute::flagVoiceChat);
|
||||
}
|
||||
|
||||
void LLParticipantList::moderateVoiceParticipant(const LLSD& param)
|
||||
{
|
||||
if (!gAgent.getRegion()) return;
|
||||
LLIMSpeakerMgr* mgr = dynamic_cast<LLIMSpeakerMgr*>(mSpeakerMgr);
|
||||
if (mgr)
|
||||
{
|
||||
mgr->moderateVoiceParticipant(mAvatarList->getValue(), param);
|
||||
}
|
||||
}
|
||||
|
||||
void LLParticipantList::moderateVoiceAllParticipants(const LLSD& param)
|
||||
{
|
||||
if (!gAgent.getRegion()) return;
|
||||
// Singu Note: moderateVoiceAllParticipants ends up flipping the boolean passed to it before the actual post
|
||||
if (LLIMSpeakerMgr* speaker_manager = dynamic_cast<LLIMSpeakerMgr*>(mSpeakerMgr))
|
||||
{
|
||||
if (param.asString() == "unmoderated")
|
||||
{
|
||||
speaker_manager->moderateVoiceAllParticipants(true);
|
||||
}
|
||||
else if (param.asString() == "moderated")
|
||||
{
|
||||
speaker_manager->moderateVoiceAllParticipants(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Singu Note: The following callbacks are not found upstream
|
||||
void LLParticipantList::onVolumeChange(const LLSD& param)
|
||||
{
|
||||
// Singu Note: Allow modifying own voice volume during a voice session (Which is valued at half of what it should be)
|
||||
const LLUUID& speaker_id = mAvatarList->getValue().asUUID();
|
||||
if (gAgentID == speaker_id)
|
||||
{
|
||||
gSavedSettings.setF32("AudioLevelMic", param.asFloat()*2);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVoiceClient::getInstance()->setUserVolume(speaker_id, param.asFloat());
|
||||
}
|
||||
}
|
||||
|
||||
void LLParticipantList::onClickProfile()
|
||||
{
|
||||
// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-1.0.0g
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) return;
|
||||
// [/RLVa:KB]
|
||||
LLAvatarActions::showProfile(mAvatarList->getValue().asUUID());
|
||||
}
|
||||
|
||||
void LLParticipantList::onSortChanged()
|
||||
{
|
||||
gSavedSettings.setString("FloaterActiveSpeakersSortColumn", mAvatarList->getSortColumnName());
|
||||
gSavedSettings.setBOOL("FloaterActiveSpeakersSortAscending", mAvatarList->getSortAscending());
|
||||
}
|
||||
|
||||
void LLParticipantList::setVoiceModerationCtrlMode(const bool& moderated_voice)
|
||||
{
|
||||
if (LLUICtrl* voice_moderation_ctrl = findChild<LLUICtrl>("moderation_mode"))
|
||||
{
|
||||
voice_moderation_ctrl->setValue(moderated_voice ? "moderated" : "unmoderated");
|
||||
}
|
||||
}
|
||||
|
||||
210
indra/newview/llparticipantlist.h
Normal file
210
indra/newview/llparticipantlist.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @file llparticipantlist.h
|
||||
* @brief LLParticipantList intended to update view(LLAvatarList) according to incoming messages
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_PARTICIPANTLIST_H
|
||||
#define LL_PARTICIPANTLIST_H
|
||||
|
||||
#include "llpanel.h"
|
||||
|
||||
class LLSpeakerMgr;
|
||||
class LLScrollListCtrl;
|
||||
class LLUICtrl;
|
||||
|
||||
class LLParticipantList : public LLPanel
|
||||
{
|
||||
LOG_CLASS(LLParticipantList);
|
||||
public:
|
||||
|
||||
typedef boost::function<bool (const LLUUID& speaker_id)> validate_speaker_callback_t;
|
||||
|
||||
LLParticipantList(LLSpeakerMgr* data_source, bool show_text_chatters);
|
||||
/*virtual*/ BOOL postBuild();
|
||||
~LLParticipantList();
|
||||
|
||||
/**
|
||||
* Adds specified avatar ID to the existing list if it is not Agent's ID
|
||||
*
|
||||
* @param[in] avatar_id - Avatar UUID to be added into the list
|
||||
*/
|
||||
void addAvatarIDExceptAgent(const LLUUID& avatar_id);
|
||||
|
||||
/**
|
||||
* Refreshes the participant list.
|
||||
*/
|
||||
void refreshSpeakers();
|
||||
|
||||
/**
|
||||
* Set a callback to be called before adding a speaker. Invalid speakers will not be added.
|
||||
*
|
||||
* If the callback is unset all speakers are considered as valid.
|
||||
*
|
||||
* @see onAddItemEvent()
|
||||
*/
|
||||
void setValidateSpeakerCallback(validate_speaker_callback_t cb);
|
||||
|
||||
void setVoiceModerationCtrlMode(const bool& moderated_voice);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* LLSpeakerMgr event handlers
|
||||
*/
|
||||
bool onAddItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
bool onRemoveItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
bool onClearListEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
//bool onModeratorUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
bool onSpeakerMuteEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
|
||||
/**
|
||||
* List of listeners implementing LLOldEvents::LLSimpleListener.
|
||||
* There is no way to handle all the events in one listener as LLSpeakerMgr registers
|
||||
* listeners in such a way that one listener can handle only one type of event
|
||||
**/
|
||||
class BaseSpeakerListener : public LLOldEvents::LLSimpleListener
|
||||
{
|
||||
public:
|
||||
BaseSpeakerListener(LLParticipantList& parent) : mParent(parent) {}
|
||||
protected:
|
||||
LLParticipantList& mParent;
|
||||
};
|
||||
|
||||
class SpeakerAddListener : public BaseSpeakerListener
|
||||
{
|
||||
public:
|
||||
SpeakerAddListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
|
||||
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
};
|
||||
|
||||
class SpeakerRemoveListener : public BaseSpeakerListener
|
||||
{
|
||||
public:
|
||||
SpeakerRemoveListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
|
||||
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
};
|
||||
|
||||
class SpeakerClearListener : public BaseSpeakerListener
|
||||
{
|
||||
public:
|
||||
SpeakerClearListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
|
||||
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
};
|
||||
|
||||
/*class SpeakerModeratorUpdateListener : public BaseSpeakerListener
|
||||
{
|
||||
public:
|
||||
SpeakerModeratorUpdateListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
|
||||
*virtual* bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
};*/
|
||||
|
||||
class SpeakerMuteListener : public BaseSpeakerListener
|
||||
{
|
||||
public:
|
||||
SpeakerMuteListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {}
|
||||
|
||||
/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata);
|
||||
};
|
||||
|
||||
/**
|
||||
* Menu used in the participant list.
|
||||
class LLParticipantListMenu : public LLListContextMenu
|
||||
{
|
||||
*/
|
||||
private:
|
||||
void toggleAllowTextChat(const LLSD& userdata);
|
||||
void toggleMute(const LLSD& userdata, U32 flags);
|
||||
void toggleMuteText();
|
||||
void toggleMuteVoice();
|
||||
|
||||
/**
|
||||
* Processes Voice moderation menu items.
|
||||
*
|
||||
* It calls either moderateVoiceParticipant() or moderateVoiceParticipant() depend on
|
||||
* passed parameter.
|
||||
*
|
||||
* @param userdata can be "selected" or "others".
|
||||
*
|
||||
* @see moderateVoiceParticipant()
|
||||
* @see moderateVoiceAllParticipants()
|
||||
*/
|
||||
void moderateVoice(const LLSD& userdata);
|
||||
|
||||
/**
|
||||
* Mutes/Unmutes avatar for current group voice chat.
|
||||
*
|
||||
* It only marks avatar as muted for session and does not use local Agent's Block list.
|
||||
* It does not mute Agent itself.
|
||||
*
|
||||
* @param[in] avatar_id UUID of avatar to be processed
|
||||
* @param[in] unmute if true - specified avatar will be muted, otherwise - unmuted.
|
||||
*
|
||||
* @see moderateVoiceAllParticipants()
|
||||
*/
|
||||
void moderateVoiceParticipant(const LLSD& param);
|
||||
|
||||
/**
|
||||
* Mutes/Unmutes all avatars for current group voice chat.
|
||||
*
|
||||
* It only marks avatars as muted for session and does not use local Agent's Block list.
|
||||
*
|
||||
* @param[in] unmute if true - avatars will be muted, otherwise - unmuted.
|
||||
*
|
||||
* @see moderateVoiceParticipant()
|
||||
*/
|
||||
void moderateVoiceAllParticipants(const LLSD& param);
|
||||
|
||||
//static void confirmMuteAllCallback(const LLSD& notification, const LLSD& response);
|
||||
//};
|
||||
|
||||
private:
|
||||
void onAvatarListDoubleClicked();
|
||||
|
||||
/**
|
||||
* Adjusts passed participant to work properly.
|
||||
*
|
||||
* Adds SpeakerMuteListener to process moderation actions.
|
||||
*/
|
||||
void adjustParticipant(const LLUUID& speaker_id);
|
||||
|
||||
// Singu Note: The following callbacks are not found upstream
|
||||
void handleSpeakerSelect();
|
||||
void onClickProfile();
|
||||
void onSortChanged();
|
||||
void onVolumeChange(const LLSD& param);
|
||||
|
||||
LLSpeakerMgr* mSpeakerMgr;
|
||||
LLScrollListCtrl* mAvatarList;
|
||||
bool mShowTextChatters;
|
||||
|
||||
LLPointer<SpeakerAddListener> mSpeakerAddListener;
|
||||
LLPointer<SpeakerRemoveListener> mSpeakerRemoveListener;
|
||||
LLPointer<SpeakerClearListener> mSpeakerClearListener;
|
||||
//LLPointer<SpeakerModeratorUpdateListener> mSpeakerModeratorListener;
|
||||
LLPointer<SpeakerMuteListener> mSpeakerMuteListener;
|
||||
|
||||
validate_speaker_callback_t mValidateSpeakerCallback;
|
||||
};
|
||||
|
||||
#endif // LL_PARTICIPANTLIST_H
|
||||
|
||||
@@ -37,11 +37,10 @@
|
||||
|
||||
#include "floatervoicelicense.h"
|
||||
#include "llcheckboxctrl.h"
|
||||
#include "llfloatervoicedevicesettings.h"
|
||||
#include "llfocusmgr.h"
|
||||
#include "llkeyboard.h"
|
||||
#include "llmodaldialog.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llpanelvoicedevicesettings.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
|
||||
@@ -97,12 +96,22 @@ void LLVoiceSetKeyDialog::onCancel(void* user_data)
|
||||
self->close();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void* createDevicePanel(void*)
|
||||
{
|
||||
return new LLPanelVoiceDeviceSettings;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//LLPrefsVoice
|
||||
LLPrefsVoice::LLPrefsVoice()
|
||||
: LLPanel(std::string("Voice Chat Panel"))
|
||||
{
|
||||
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_voice.xml");
|
||||
{
|
||||
mFactoryMap["device_settings_panel"] = LLCallbackMap(createDevicePanel, NULL);
|
||||
|
||||
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_voice.xml", &getFactoryMap());
|
||||
}
|
||||
|
||||
LLPrefsVoice::~LLPrefsVoice()
|
||||
@@ -114,7 +123,6 @@ BOOL LLPrefsVoice::postBuild()
|
||||
childSetCommitCallback("enable_voice_check", onCommitEnableVoiceChat, this);
|
||||
childSetAction("set_voice_hotkey_button", onClickSetKey, this);
|
||||
childSetAction("set_voice_middlemouse_button", onClickSetMiddleMouse, this);
|
||||
childSetAction("device_settings_btn", onClickVoiceDeviceSettings, this);
|
||||
|
||||
BOOL voice_disabled = gSavedSettings.getBOOL("CmdLineDisableVoice");
|
||||
childSetVisible("voice_unavailable", voice_disabled);
|
||||
@@ -132,6 +140,8 @@ BOOL LLPrefsVoice::postBuild()
|
||||
childSetValue("ear_location", gSavedSettings.getS32("VoiceEarLocation"));
|
||||
childSetValue("enable_lip_sync_check", gSavedSettings.getBOOL("LipSyncEnabled"));
|
||||
|
||||
gSavedSettings.getControl("ShowDeviceSettings")->getSignal()->connect(boost::bind(&LLPanel::childSetVisible, this, "device_settings_panel", _2)); // Singu TODO: visibility_control
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -144,8 +154,7 @@ void LLPrefsVoice::apply()
|
||||
gSavedSettings.setS32("VoiceEarLocation", childGetValue("ear_location"));
|
||||
gSavedSettings.setBOOL("LipSyncEnabled", childGetValue("enable_lip_sync_check"));
|
||||
|
||||
LLFloaterVoiceDeviceSettings* voice_device_settings = LLFloaterVoiceDeviceSettings::getInstance();
|
||||
if(voice_device_settings)
|
||||
if (LLPanelVoiceDeviceSettings* voice_device_settings = getChild<LLPanelVoiceDeviceSettings>("device_settings_panel"))
|
||||
{
|
||||
voice_device_settings->apply();
|
||||
}
|
||||
@@ -165,8 +174,7 @@ void LLPrefsVoice::apply()
|
||||
|
||||
void LLPrefsVoice::cancel()
|
||||
{
|
||||
LLFloaterVoiceDeviceSettings* voice_device_settings = LLFloaterVoiceDeviceSettings::getInstance();
|
||||
if(voice_device_settings)
|
||||
if (LLPanelVoiceDeviceSettings* voice_device_settings = getChild<LLPanelVoiceDeviceSettings>("device_settings_panel"))
|
||||
{
|
||||
voice_device_settings->cancel();
|
||||
}
|
||||
@@ -186,7 +194,6 @@ void LLPrefsVoice::onCommitEnableVoiceChat(LLUICtrl* ctrl, void* user_data)
|
||||
bool enable = enable_voice_chat->getValue();
|
||||
|
||||
self->childSetEnabled("modifier_combo", enable);
|
||||
//self->childSetEnabled("friends_only_check", enable);
|
||||
self->childSetEnabled("push_to_talk_label", enable);
|
||||
self->childSetEnabled("voice_call_friends_only_check", enable);
|
||||
self->childSetEnabled("auto_disengage_mic_check", enable);
|
||||
@@ -196,6 +203,7 @@ void LLPrefsVoice::onCommitEnableVoiceChat(LLUICtrl* ctrl, void* user_data)
|
||||
self->childSetEnabled("set_voice_hotkey_button", enable);
|
||||
self->childSetEnabled("set_voice_middlemouse_button", enable);
|
||||
self->childSetEnabled("device_settings_btn", enable);
|
||||
self->childSetEnabled("device_settings_panel", enable);
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -213,15 +221,3 @@ void LLPrefsVoice::onClickSetMiddleMouse(void* user_data)
|
||||
self->childSetValue("modifier_combo", "MiddleMouse");
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrefsVoice::onClickVoiceDeviceSettings(void* user_data)
|
||||
{
|
||||
LLPrefsVoice* voice_prefs = (LLPrefsVoice*)user_data;
|
||||
LLFloaterVoiceDeviceSettings* device_settings_floater = LLFloaterVoiceDeviceSettings::showInstance();
|
||||
LLFloater* parent_floater = gFloaterView->getParentFloater(voice_prefs);
|
||||
if(parent_floater)
|
||||
{
|
||||
parent_floater->addDependentFloater(device_settings_floater, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ private:
|
||||
static void onCommitEnableVoiceChat(LLUICtrl* ctrl, void* user_data);
|
||||
static void onClickSetKey(void* user_data);
|
||||
static void onClickSetMiddleMouse(void* user_data);
|
||||
static void onClickVoiceDeviceSettings(void* user_data);
|
||||
};
|
||||
|
||||
#endif // LLPREFSVOICE_H
|
||||
|
||||
960
indra/newview/llspeakers.cpp
Normal file
960
indra/newview/llspeakers.cpp
Normal file
@@ -0,0 +1,960 @@
|
||||
/**
|
||||
* @file llspeakers.cpp
|
||||
* @brief Management interface for muting and controlling volume of residents currently speaking
|
||||
*
|
||||
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llspeakers.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llimpanel.h" // For LLFloaterIMPanel
|
||||
#include "llimview.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llui.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "llworld.h"
|
||||
|
||||
#include "rlvhandler.h"
|
||||
|
||||
extern AIHTTPTimeoutPolicy moderationResponder_timeout;
|
||||
|
||||
const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f);
|
||||
const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f);
|
||||
|
||||
LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) :
|
||||
mStatus(LLSpeaker::STATUS_TEXT_ONLY),
|
||||
mLastSpokeTime(0.f),
|
||||
mSpeechVolume(0.f),
|
||||
mHasSpoken(FALSE),
|
||||
mHasLeftCurrentCall(FALSE),
|
||||
mDotColor(LLColor4::white),
|
||||
mID(id),
|
||||
mTyping(FALSE),
|
||||
mSortIndex(0),
|
||||
mType(type),
|
||||
mIsModerator(FALSE),
|
||||
mModeratorMutedVoice(FALSE),
|
||||
mModeratorMutedText(FALSE)
|
||||
{
|
||||
// Make sure we also get the display name if SLIM or some other external voice client is used and not whatever is provided.
|
||||
if ((name.empty() && type == SPEAKER_AGENT) || type == SPEAKER_EXTERNAL)
|
||||
{
|
||||
lookupName();
|
||||
}
|
||||
else
|
||||
{
|
||||
mDisplayName = name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLSpeaker::lookupName()
|
||||
{
|
||||
if (mDisplayName.empty())
|
||||
{
|
||||
// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-1.0.0g
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && gAgentID != mID)
|
||||
mDisplayName = RlvStrings::getAnonym(mDisplayName);
|
||||
else
|
||||
// [/RLVa:KB]
|
||||
LLAvatarNameCache::get(mID, boost::bind(&LLSpeaker::onNameCache, this, _2));
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpeaker::onNameCache(const LLAvatarName& full_name)
|
||||
{
|
||||
LLAvatarNameCache::getPNSName(full_name, mDisplayName);
|
||||
}
|
||||
|
||||
bool LLSpeaker::isInVoiceChannel()
|
||||
{
|
||||
return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED;
|
||||
}
|
||||
|
||||
LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source)
|
||||
: LLEvent(source, "Speaker add moderator event"),
|
||||
mSpeakerID (source->mID),
|
||||
mIsModerator (source->mIsModerator)
|
||||
{
|
||||
}
|
||||
|
||||
LLSD LLSpeakerUpdateModeratorEvent::getValue()
|
||||
{
|
||||
LLSD ret;
|
||||
ret["id"] = mSpeakerID;
|
||||
ret["is_moderator"] = mIsModerator;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source)
|
||||
: LLEvent(source, "Speaker text moderation event")
|
||||
{
|
||||
}
|
||||
|
||||
LLSD LLSpeakerTextModerationEvent::getValue()
|
||||
{
|
||||
return std::string("text");
|
||||
}
|
||||
|
||||
|
||||
LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source)
|
||||
: LLEvent(source, "Speaker voice moderation event")
|
||||
{
|
||||
}
|
||||
|
||||
LLSD LLSpeakerVoiceModerationEvent::getValue()
|
||||
{
|
||||
return std::string("voice");
|
||||
}
|
||||
|
||||
LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id)
|
||||
: LLEvent(source, "Speaker added/removed from speaker mgr"),
|
||||
mSpeakerID(speaker_id)
|
||||
{
|
||||
}
|
||||
|
||||
LLSD LLSpeakerListChangeEvent::getValue()
|
||||
{
|
||||
return mSpeakerID;
|
||||
}
|
||||
|
||||
// helper sort class
|
||||
struct LLSortRecentSpeakers
|
||||
{
|
||||
bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const;
|
||||
};
|
||||
|
||||
bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const
|
||||
{
|
||||
// Sort first on status
|
||||
if (lhs->mStatus != rhs->mStatus)
|
||||
{
|
||||
return (lhs->mStatus < rhs->mStatus);
|
||||
}
|
||||
|
||||
// and then on last speaking time
|
||||
if(lhs->mLastSpokeTime != rhs->mLastSpokeTime)
|
||||
{
|
||||
return (lhs->mLastSpokeTime > rhs->mLastSpokeTime);
|
||||
}
|
||||
|
||||
// and finally (only if those are both equal), on name.
|
||||
return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 );
|
||||
}
|
||||
|
||||
LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id)
|
||||
: LLEventTimer(action_period)
|
||||
, mActionCallback(action_cb)
|
||||
, mSpeakerId(speaker_id)
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLSpeakerActionTimer::tick()
|
||||
{
|
||||
if (mActionCallback)
|
||||
{
|
||||
return (BOOL)mActionCallback(mSpeakerId);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLSpeakerActionTimer::unset()
|
||||
{
|
||||
mActionCallback = 0;
|
||||
}
|
||||
|
||||
LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay)
|
||||
: mActionCallback(action_cb)
|
||||
, mActionDelay(action_delay)
|
||||
{
|
||||
}
|
||||
|
||||
LLSpeakersDelayActionsStorage::~LLSpeakersDelayActionsStorage()
|
||||
{
|
||||
removeAllTimers();
|
||||
}
|
||||
|
||||
void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id)
|
||||
{
|
||||
bool not_found = true;
|
||||
if (mActionTimersMap.size() > 0)
|
||||
{
|
||||
not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end();
|
||||
}
|
||||
|
||||
// If there is already a started timer for the passed UUID don't do anything.
|
||||
if (not_found)
|
||||
{
|
||||
// Starting a timer to remove an participant after delay is completed
|
||||
mActionTimersMap.insert(LLSpeakerActionTimer::action_value_t(speaker_id,
|
||||
new LLSpeakerActionTimer(
|
||||
boost::bind(&LLSpeakersDelayActionsStorage::onTimerActionCallback, this, _1),
|
||||
mActionDelay, speaker_id)));
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpeakersDelayActionsStorage::unsetActionTimer(const LLUUID& speaker_id)
|
||||
{
|
||||
if (mActionTimersMap.size() == 0) return;
|
||||
|
||||
LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id);
|
||||
|
||||
if (it_speaker != mActionTimersMap.end())
|
||||
{
|
||||
it_speaker->second->unset();
|
||||
mActionTimersMap.erase(it_speaker);
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpeakersDelayActionsStorage::removeAllTimers()
|
||||
{
|
||||
LLSpeakerActionTimer::action_timer_iter_t iter = mActionTimersMap.begin();
|
||||
for (; iter != mActionTimersMap.end(); ++iter)
|
||||
{
|
||||
delete iter->second;
|
||||
}
|
||||
mActionTimersMap.clear();
|
||||
}
|
||||
|
||||
bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_id)
|
||||
{
|
||||
unsetActionTimer(speaker_id);
|
||||
|
||||
if (mActionCallback)
|
||||
{
|
||||
mActionCallback(speaker_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLSpeakerMgr
|
||||
//
|
||||
|
||||
LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :
|
||||
mVoiceChannel(channelp)
|
||||
, mVoiceModerated(false)
|
||||
, mModerateModeHandledFirstTime(false)
|
||||
{
|
||||
static LLUICachedControl<F32> remove_delay ("SpeakerParticipantRemoveDelay", 10.0);
|
||||
|
||||
mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay);
|
||||
}
|
||||
|
||||
LLSpeakerMgr::~LLSpeakerMgr()
|
||||
{
|
||||
delete mSpeakerDelayRemover;
|
||||
}
|
||||
|
||||
LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
|
||||
{
|
||||
if (id.isNull()) return NULL;
|
||||
|
||||
LLPointer<LLSpeaker> speakerp;
|
||||
if (mSpeakers.find(id) == mSpeakers.end())
|
||||
{
|
||||
speakerp = new LLSpeaker(id, name, type);
|
||||
speakerp->mStatus = status;
|
||||
mSpeakers.insert(std::make_pair(speakerp->mID, speakerp));
|
||||
mSpeakersSorted.push_back(speakerp);
|
||||
LL_DEBUGS("Speakers") << "Added speaker " << id << llendl;
|
||||
fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add");
|
||||
}
|
||||
else
|
||||
{
|
||||
speakerp = findSpeaker(id);
|
||||
if (speakerp.notNull())
|
||||
{
|
||||
// keep highest priority status (lowest value) instead of overriding current value
|
||||
speakerp->mStatus = llmin(speakerp->mStatus, status);
|
||||
// RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id
|
||||
// we need to override speakers that we think are objects when we find out they are really
|
||||
// residents
|
||||
if (type == LLSpeaker::SPEAKER_AGENT)
|
||||
{
|
||||
speakerp->mType = LLSpeaker::SPEAKER_AGENT;
|
||||
speakerp->lookupName();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Speakers") << "Speaker " << id << " not found" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
mSpeakerDelayRemover->unsetActionTimer(speakerp->mID);
|
||||
return speakerp;
|
||||
}
|
||||
|
||||
// *TODO: Once way to request the current voice channel moderation mode is implemented
|
||||
// this method with related code should be removed.
|
||||
/*
|
||||
Initializes "moderate_mode" of voice session on first join.
|
||||
|
||||
This is WORKAROUND because a way to request the current voice channel moderation mode exists
|
||||
but is not implemented in viewer yet. See EXT-6937.
|
||||
*/
|
||||
void LLSpeakerMgr::initVoiceModerateMode()
|
||||
{
|
||||
if (!mModerateModeHandledFirstTime && (mVoiceChannel && mVoiceChannel->isActive()))
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp;
|
||||
|
||||
if (mSpeakers.find(gAgentID) != mSpeakers.end())
|
||||
{
|
||||
speakerp = mSpeakers[gAgentID];
|
||||
}
|
||||
|
||||
if (speakerp.notNull())
|
||||
{
|
||||
mVoiceModerated = speakerp->mModeratorMutedVoice;
|
||||
mModerateModeHandledFirstTime = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpeakerMgr::update(BOOL resort_ok)
|
||||
{
|
||||
if (!LLVoiceClient::instanceExists())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLColor4 speaking_color = gSavedSettings.getColor4("SpeakingColor");
|
||||
LLColor4 overdriven_color = gSavedSettings.getColor4("OverdrivenColor");
|
||||
|
||||
if(resort_ok) // only allow list changes when user is not interacting with it
|
||||
{
|
||||
updateSpeakerList();
|
||||
}
|
||||
|
||||
// update status of all current speakers
|
||||
BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
|
||||
for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)
|
||||
{
|
||||
LLUUID speaker_id = speaker_it->first;
|
||||
LLSpeaker* speakerp = speaker_it->second;
|
||||
|
||||
speaker_it++;
|
||||
|
||||
if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id))
|
||||
{
|
||||
speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id);
|
||||
BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id);
|
||||
if (moderator_muted_voice != speakerp->mModeratorMutedVoice)
|
||||
{
|
||||
speakerp->mModeratorMutedVoice = moderator_muted_voice;
|
||||
LL_DEBUGS("Speakers") << (speakerp->mModeratorMutedVoice? "Muted" : "Umuted") << " speaker " << speaker_id<< llendl;
|
||||
speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp));
|
||||
}
|
||||
|
||||
if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice)
|
||||
{
|
||||
speakerp->mStatus = LLSpeaker::STATUS_MUTED;
|
||||
}
|
||||
else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id))
|
||||
{
|
||||
// reset inactivity expiration
|
||||
if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING)
|
||||
{
|
||||
speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
|
||||
speakerp->mHasSpoken = TRUE;
|
||||
}
|
||||
speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
|
||||
// interpolate between active color and full speaking color based on power of speech output
|
||||
speakerp->mDotColor = speaking_color;
|
||||
if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL)
|
||||
{
|
||||
speakerp->mDotColor = overdriven_color;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
speakerp->mSpeechVolume = 0.f;
|
||||
speakerp->mDotColor = ACTIVE_COLOR;
|
||||
|
||||
if (speakerp->mHasSpoken)
|
||||
{
|
||||
// have spoken once, not currently speaking
|
||||
speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default state for being in voice channel
|
||||
speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// speaker no longer registered in voice channel, demote to text only
|
||||
else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL)
|
||||
{
|
||||
if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL)
|
||||
{
|
||||
// external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice)
|
||||
setSpeakerNotInChannel(speakerp); // Singu Note: Don't just flag, call the flagging function and get them on the removal timer!
|
||||
}
|
||||
else
|
||||
{
|
||||
speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY;
|
||||
speakerp->mSpeechVolume = 0.f;
|
||||
speakerp->mDotColor = ACTIVE_COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(resort_ok) // only allow list changes when user is not interacting with it
|
||||
{
|
||||
// sort by status then time last spoken
|
||||
std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers());
|
||||
}
|
||||
|
||||
// for recent speakers who are not currently speaking, show "recent" color dot for most recent
|
||||
// fading to "active" color
|
||||
|
||||
S32 recent_speaker_count = 0;
|
||||
S32 sort_index = 0;
|
||||
speaker_list_t::iterator sorted_speaker_it;
|
||||
for(sorted_speaker_it = mSpeakersSorted.begin();
|
||||
sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = *sorted_speaker_it;
|
||||
|
||||
// color code recent speakers who are not currently speaking
|
||||
if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN)
|
||||
{
|
||||
speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f));
|
||||
recent_speaker_count++;
|
||||
}
|
||||
|
||||
// stuff sort ordinal into speaker so the ui can sort by this value
|
||||
speakerp->mSortIndex = sort_index++;
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpeakerMgr::updateSpeakerList()
|
||||
{
|
||||
// are we bound to the currently active voice channel?
|
||||
if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()))
|
||||
{
|
||||
std::set<LLUUID> participants;
|
||||
LLVoiceClient::getInstance()->getParticipantList(participants);
|
||||
// add new participants to our list of known speakers
|
||||
for (std::set<LLUUID>::iterator participant_it = participants.begin();
|
||||
participant_it != participants.end();
|
||||
++participant_it)
|
||||
{
|
||||
setSpeaker(*participant_it,
|
||||
LLVoiceClient::getInstance()->getDisplayName(*participant_it),
|
||||
LLSpeaker::STATUS_VOICE_ACTIVE,
|
||||
(LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpeakerMgr::setSpeakerNotInChannel(LLSpeaker* speakerp)
|
||||
{
|
||||
speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
|
||||
speakerp->mDotColor = INACTIVE_COLOR;
|
||||
mSpeakerDelayRemover->setActionTimer(speakerp->mID);
|
||||
}
|
||||
|
||||
bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id)
|
||||
{
|
||||
mSpeakers.erase(speaker_id);
|
||||
|
||||
speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin();
|
||||
|
||||
for(; sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it)
|
||||
{
|
||||
if (speaker_id == (*sorted_speaker_it)->mID)
|
||||
{
|
||||
mSpeakersSorted.erase(sorted_speaker_it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LL_DEBUGS("Speakers") << "Removed speaker " << speaker_id << llendl;
|
||||
fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove");
|
||||
|
||||
update(TRUE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id)
|
||||
{
|
||||
//In some conditions map causes crash if it is empty(Windows only), adding check (EK)
|
||||
if (mSpeakers.size() == 0)
|
||||
return NULL;
|
||||
speaker_map_t::iterator found_it = mSpeakers.find(speaker_id);
|
||||
if (found_it == mSpeakers.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return found_it->second;
|
||||
}
|
||||
|
||||
void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text)
|
||||
{
|
||||
speaker_list->clear();
|
||||
for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = speaker_it->second;
|
||||
// what about text only muted or inactive?
|
||||
if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY)
|
||||
{
|
||||
speaker_list->push_back(speakerp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LLUUID LLSpeakerMgr::getSessionID()
|
||||
{
|
||||
return mVoiceChannel->getSessionID();
|
||||
}
|
||||
|
||||
|
||||
void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
|
||||
if (speakerp.notNull())
|
||||
{
|
||||
speakerp->mTyping = typing;
|
||||
}
|
||||
}
|
||||
|
||||
// speaker has chatted via either text or voice
|
||||
void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
|
||||
if (speakerp.notNull())
|
||||
{
|
||||
speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
|
||||
speakerp->mHasSpoken = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLSpeakerMgr::isVoiceActive()
|
||||
{
|
||||
// mVoiceChannel = NULL means current voice channel, whatever it is
|
||||
return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLIMSpeakerMgr
|
||||
//
|
||||
LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel)
|
||||
{
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::updateSpeakerList()
|
||||
{
|
||||
// don't do normal updates which are pulled from voice channel
|
||||
// rely on user list reported by sim
|
||||
|
||||
// We need to do this to allow PSTN callers into group chats to show in the list.
|
||||
LLSpeakerMgr::updateSpeakerList();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers)
|
||||
{
|
||||
if ( !speakers.isMap() ) return;
|
||||
|
||||
if ( speakers.has("agent_info") && speakers["agent_info"].isMap() )
|
||||
{
|
||||
LLSD::map_const_iterator speaker_it;
|
||||
for(speaker_it = speakers["agent_info"].beginMap();
|
||||
speaker_it != speakers["agent_info"].endMap();
|
||||
++speaker_it)
|
||||
{
|
||||
LLUUID agent_id(speaker_it->first);
|
||||
|
||||
LLPointer<LLSpeaker> speakerp = setSpeaker(
|
||||
agent_id,
|
||||
LLStringUtil::null,
|
||||
LLSpeaker::STATUS_TEXT_ONLY);
|
||||
|
||||
if ( speaker_it->second.isMap() )
|
||||
{
|
||||
BOOL is_moderator = speakerp->mIsModerator;
|
||||
speakerp->mIsModerator = speaker_it->second["is_moderator"];
|
||||
speakerp->mModeratorMutedText =
|
||||
speaker_it->second["mutes"]["text"];
|
||||
// Fire event only if moderator changed
|
||||
if ( is_moderator != speakerp->mIsModerator )
|
||||
{
|
||||
LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << llendl;
|
||||
fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( speakers.has("agents" ) && speakers["agents"].isArray() )
|
||||
{
|
||||
//older, more decprecated way. Need here for
|
||||
//using older version of servers
|
||||
LLSD::array_const_iterator speaker_it;
|
||||
for(speaker_it = speakers["agents"].beginArray();
|
||||
speaker_it != speakers["agents"].endArray();
|
||||
++speaker_it)
|
||||
{
|
||||
const LLUUID agent_id = (*speaker_it).asUUID();
|
||||
|
||||
LLPointer<LLSpeaker> speakerp = setSpeaker(
|
||||
agent_id,
|
||||
LLStringUtil::null,
|
||||
LLSpeaker::STATUS_TEXT_ONLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
|
||||
{
|
||||
if ( !update.isMap() ) return;
|
||||
|
||||
if ( update.has("agent_updates") && update["agent_updates"].isMap() )
|
||||
{
|
||||
LLSD::map_const_iterator update_it;
|
||||
for(
|
||||
update_it = update["agent_updates"].beginMap();
|
||||
update_it != update["agent_updates"].endMap();
|
||||
++update_it)
|
||||
{
|
||||
LLUUID agent_id(update_it->first);
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
|
||||
|
||||
LLSD agent_data = update_it->second;
|
||||
|
||||
if (agent_data.isMap() && agent_data.has("transition"))
|
||||
{
|
||||
if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull())
|
||||
{
|
||||
setSpeakerNotInChannel(speakerp);
|
||||
}
|
||||
else if (agent_data["transition"].asString() == "ENTER")
|
||||
{
|
||||
// add or update speaker
|
||||
speakerp = setSpeaker(agent_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
if (speakerp.isNull()) continue;
|
||||
|
||||
// should have a valid speaker from this point on
|
||||
if (agent_data.isMap() && agent_data.has("info"))
|
||||
{
|
||||
LLSD agent_info = agent_data["info"];
|
||||
|
||||
if (agent_info.has("is_moderator"))
|
||||
{
|
||||
BOOL is_moderator = speakerp->mIsModerator;
|
||||
speakerp->mIsModerator = agent_info["is_moderator"];
|
||||
// Fire event only if moderator changed
|
||||
if ( is_moderator != speakerp->mIsModerator )
|
||||
{
|
||||
LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << llendl;
|
||||
fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator");
|
||||
}
|
||||
}
|
||||
|
||||
if (agent_info.has("mutes"))
|
||||
{
|
||||
speakerp->mModeratorMutedText = agent_info["mutes"]["text"];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( update.has("updates") && update["updates"].isMap() )
|
||||
{
|
||||
LLSD::map_const_iterator update_it;
|
||||
for (
|
||||
update_it = update["updates"].beginMap();
|
||||
update_it != update["updates"].endMap();
|
||||
++update_it)
|
||||
{
|
||||
LLUUID agent_id(update_it->first);
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
|
||||
|
||||
std::string agent_transition = update_it->second.asString();
|
||||
if (agent_transition == "LEAVE" && speakerp.notNull())
|
||||
{
|
||||
setSpeakerNotInChannel(speakerp);
|
||||
}
|
||||
else if ( agent_transition == "ENTER")
|
||||
{
|
||||
// add or update speaker
|
||||
speakerp = setSpeaker(agent_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "bad membership list update "
|
||||
<< agent_transition << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ModerationResponder : public LLHTTPClient::ResponderIgnoreBody
|
||||
{
|
||||
public:
|
||||
ModerationResponder(const LLUUID& session_id)
|
||||
{
|
||||
mSessionID = session_id;
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
{
|
||||
llwarns << "ModerationResponder error [status:" << status << "]: " << reason << llendl;
|
||||
|
||||
if ( gIMMgr )
|
||||
{
|
||||
LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(mSessionID);
|
||||
if (!floaterp) return;
|
||||
|
||||
//403 == you're not a mod
|
||||
//should be disabled if you're not a moderator
|
||||
if ( 403 == status )
|
||||
{
|
||||
floaterp->showSessionEventError(
|
||||
"mute",
|
||||
"not_a_mod_error");
|
||||
}
|
||||
else
|
||||
{
|
||||
floaterp->showSessionEventError(
|
||||
"mute",
|
||||
"generic_request_error");
|
||||
}
|
||||
}
|
||||
}
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return moderationResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "ModerationResponder"; }
|
||||
|
||||
private:
|
||||
LLUUID mSessionID;
|
||||
};
|
||||
|
||||
void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
|
||||
if (!speakerp) return;
|
||||
|
||||
std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
|
||||
LLSD data;
|
||||
data["method"] = "mute update";
|
||||
data["session-id"] = getSessionID();
|
||||
data["params"] = LLSD::emptyMap();
|
||||
data["params"]["agent_id"] = speaker_id;
|
||||
data["params"]["mute_info"] = LLSD::emptyMap();
|
||||
//current value represents ability to type, so invert
|
||||
data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText;
|
||||
|
||||
LLHTTPClient::post(url, data, new ModerationResponder(getSessionID()));
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(avatar_id);
|
||||
if (!speakerp) return;
|
||||
|
||||
// *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for
|
||||
// text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE)
|
||||
bool is_in_voice = speakerp->mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || speakerp->mStatus == LLSpeaker::STATUS_MUTED;
|
||||
|
||||
// do not send voice moderation changes for avatars not in voice channel
|
||||
if (!is_in_voice) return;
|
||||
|
||||
std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
|
||||
LLSD data;
|
||||
data["method"] = "mute update";
|
||||
data["session-id"] = getSessionID();
|
||||
data["params"] = LLSD::emptyMap();
|
||||
data["params"]["agent_id"] = avatar_id;
|
||||
data["params"]["mute_info"] = LLSD::emptyMap();
|
||||
data["params"]["mute_info"]["voice"] = !unmute;
|
||||
|
||||
LLHTTPClient::post(
|
||||
url,
|
||||
data,
|
||||
new ModerationResponder(getSessionID()));
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::moderateVoiceAllParticipants( bool unmute_everyone )
|
||||
{
|
||||
if (mVoiceModerated == !unmute_everyone)
|
||||
{
|
||||
// session already in requested state. Just force participants which do not match it.
|
||||
forceVoiceModeratedMode(mVoiceModerated);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise set moderated mode for a whole session.
|
||||
moderateVoiceSession(getSessionID(), !unmute_everyone);
|
||||
}
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::processSessionUpdate(const LLSD& session_update)
|
||||
{
|
||||
if (session_update.has("moderated_mode") &&
|
||||
session_update["moderated_mode"].has("voice"))
|
||||
{
|
||||
mVoiceModerated = session_update["moderated_mode"]["voice"];
|
||||
}
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallow_voice)
|
||||
{
|
||||
std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
|
||||
LLSD data;
|
||||
data["method"] = "session update";
|
||||
data["session-id"] = session_id;
|
||||
data["params"] = LLSD::emptyMap();
|
||||
|
||||
data["params"]["update_info"] = LLSD::emptyMap();
|
||||
|
||||
data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap();
|
||||
data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice;
|
||||
|
||||
LLHTTPClient::post(url, data, new ModerationResponder(session_id));
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted)
|
||||
{
|
||||
for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
|
||||
{
|
||||
LLUUID speaker_id = speaker_it->first;
|
||||
LLSpeaker* speakerp = speaker_it->second;
|
||||
|
||||
// participant does not match requested state
|
||||
if (should_be_muted != (bool)speakerp->mModeratorMutedVoice)
|
||||
{
|
||||
moderateVoiceParticipant(speaker_id, !should_be_muted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLActiveSpeakerMgr
|
||||
//
|
||||
|
||||
LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void LLActiveSpeakerMgr::updateSpeakerList()
|
||||
{
|
||||
// point to whatever the current voice channel is
|
||||
mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
|
||||
|
||||
// always populate from active voice channel
|
||||
if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false
|
||||
{
|
||||
LL_DEBUGS("Speakers") << "Removed all speakers" << llendl;
|
||||
fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear");
|
||||
mSpeakers.clear();
|
||||
mSpeakersSorted.clear();
|
||||
mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
|
||||
mSpeakerDelayRemover->removeAllTimers();
|
||||
}
|
||||
LLSpeakerMgr::updateSpeakerList();
|
||||
|
||||
// clean up text only speakers
|
||||
for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
|
||||
{
|
||||
LLUUID speaker_id = speaker_it->first;
|
||||
LLSpeaker* speakerp = speaker_it->second;
|
||||
if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
|
||||
{
|
||||
// automatically flag text only speakers for removal
|
||||
setSpeakerNotInChannel(speakerp); // Singu Note: Don't just flag, call the flagging function and get them on the removal timer!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// LLLocalSpeakerMgr
|
||||
//
|
||||
|
||||
LLLocalSpeakerMgr::LLLocalSpeakerMgr() : LLSpeakerMgr(LLVoiceChannelProximal::getInstance())
|
||||
{
|
||||
}
|
||||
|
||||
LLLocalSpeakerMgr::~LLLocalSpeakerMgr ()
|
||||
{
|
||||
}
|
||||
|
||||
void LLLocalSpeakerMgr::updateSpeakerList()
|
||||
{
|
||||
// pull speakers from voice channel
|
||||
LLSpeakerMgr::updateSpeakerList();
|
||||
|
||||
if (gDisconnected)//the world is cleared.
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
// pick up non-voice speakers in chat range
|
||||
uuid_vec_t avatar_ids;
|
||||
std::vector<LLVector3d> positions;
|
||||
LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS);
|
||||
for(U32 i=0; i<avatar_ids.size(); i++)
|
||||
{
|
||||
setSpeaker(avatar_ids[i]);
|
||||
}
|
||||
|
||||
// check if text only speakers have moved out of chat range
|
||||
for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
|
||||
{
|
||||
LLUUID speaker_id = speaker_it->first;
|
||||
LLSpeaker* speakerp = speaker_it->second;
|
||||
if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
|
||||
{
|
||||
LLVOAvatar* avatarp = gObjectList.findAvatar(speaker_id);
|
||||
if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS_SQUARED)
|
||||
{
|
||||
setSpeakerNotInChannel(speakerp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
347
indra/newview/llspeakers.h
Normal file
347
indra/newview/llspeakers.h
Normal file
@@ -0,0 +1,347 @@
|
||||
/**
|
||||
* @file llspeakers.h
|
||||
* @brief Management interface for muting and controlling volume of residents currently speaking
|
||||
*
|
||||
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLSPEAKERS_H
|
||||
#define LL_LLSPEAKERS_H
|
||||
|
||||
#include "llevent.h"
|
||||
#include "lleventtimer.h"
|
||||
#include "llhandle.h"
|
||||
|
||||
class LLAvatarName;
|
||||
class LLSpeakerMgr;
|
||||
class LLVoiceChannel;
|
||||
|
||||
// data for a given participant in a voice channel
|
||||
class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable
|
||||
{
|
||||
public:
|
||||
typedef enum e_speaker_type
|
||||
{
|
||||
SPEAKER_AGENT,
|
||||
SPEAKER_OBJECT,
|
||||
SPEAKER_EXTERNAL // Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group)
|
||||
} ESpeakerType;
|
||||
|
||||
typedef enum e_speaker_status
|
||||
{
|
||||
STATUS_SPEAKING,
|
||||
STATUS_HAS_SPOKEN,
|
||||
STATUS_VOICE_ACTIVE,
|
||||
STATUS_TEXT_ONLY,
|
||||
STATUS_NOT_IN_CHANNEL,
|
||||
STATUS_MUTED
|
||||
} ESpeakerStatus;
|
||||
|
||||
|
||||
LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT);
|
||||
~LLSpeaker() {};
|
||||
void lookupName();
|
||||
|
||||
void onNameCache(const LLAvatarName& full_name);
|
||||
|
||||
bool isInVoiceChannel();
|
||||
|
||||
ESpeakerStatus mStatus; // current activity status in speech group
|
||||
F32 mLastSpokeTime; // timestamp when this speaker last spoke
|
||||
F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?)
|
||||
std::string mDisplayName; // cache user name for this speaker
|
||||
BOOL mHasSpoken; // has this speaker said anything this session?
|
||||
BOOL mHasLeftCurrentCall; // has this speaker left the current voice call?
|
||||
LLColor4 mDotColor;
|
||||
LLUUID mID;
|
||||
BOOL mTyping;
|
||||
S32 mSortIndex;
|
||||
ESpeakerType mType;
|
||||
BOOL mIsModerator;
|
||||
BOOL mModeratorMutedVoice;
|
||||
BOOL mModeratorMutedText;
|
||||
};
|
||||
|
||||
class LLSpeakerUpdateModeratorEvent : public LLOldEvents::LLEvent
|
||||
{
|
||||
public:
|
||||
LLSpeakerUpdateModeratorEvent(LLSpeaker* source);
|
||||
/*virtual*/ LLSD getValue();
|
||||
private:
|
||||
const LLUUID& mSpeakerID;
|
||||
BOOL mIsModerator;
|
||||
};
|
||||
|
||||
class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent
|
||||
{
|
||||
public:
|
||||
LLSpeakerTextModerationEvent(LLSpeaker* source);
|
||||
/*virtual*/ LLSD getValue();
|
||||
};
|
||||
|
||||
class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent
|
||||
{
|
||||
public:
|
||||
LLSpeakerVoiceModerationEvent(LLSpeaker* source);
|
||||
/*virtual*/ LLSD getValue();
|
||||
};
|
||||
|
||||
class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent
|
||||
{
|
||||
public:
|
||||
LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id);
|
||||
/*virtual*/ LLSD getValue();
|
||||
|
||||
private:
|
||||
const LLUUID& mSpeakerID;
|
||||
};
|
||||
|
||||
/**
|
||||
* class LLSpeakerActionTimer
|
||||
*
|
||||
* Implements a timer that calls stored callback action for stored speaker after passed period.
|
||||
*
|
||||
* Action is called until callback returns "true".
|
||||
* In this case the timer will be removed via LLEventTimer::updateClass().
|
||||
* Otherwise it should be deleted manually in place where it is used.
|
||||
* If action callback is not set timer will tick only once and deleted.
|
||||
*/
|
||||
class LLSpeakerActionTimer : public LLEventTimer
|
||||
{
|
||||
public:
|
||||
typedef boost::function<bool(const LLUUID&)> action_callback_t;
|
||||
typedef std::map<LLUUID, LLSpeakerActionTimer*> action_timers_map_t;
|
||||
typedef action_timers_map_t::value_type action_value_t;
|
||||
typedef action_timers_map_t::const_iterator action_timer_const_iter_t;
|
||||
typedef action_timers_map_t::iterator action_timer_iter_t;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param action_cb - callback which will be called each time after passed action period.
|
||||
* @param action_period - time in seconds timer should tick.
|
||||
* @param speaker_id - LLUUID of speaker which will be passed into action callback.
|
||||
*/
|
||||
LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id);
|
||||
virtual ~LLSpeakerActionTimer() {};
|
||||
|
||||
/**
|
||||
* Implements timer "tick".
|
||||
*
|
||||
* If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass().
|
||||
*/
|
||||
virtual BOOL tick();
|
||||
|
||||
/**
|
||||
* Clears the callback.
|
||||
*
|
||||
* Use this instead of deleteing this object.
|
||||
* The next call to tick() will return true and that will destroy this object.
|
||||
*/
|
||||
void unset();
|
||||
private:
|
||||
action_callback_t mActionCallback;
|
||||
LLUUID mSpeakerId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a functionality to store actions for speakers with delay.
|
||||
* Is based on LLSpeakerActionTimer.
|
||||
*/
|
||||
class LLSpeakersDelayActionsStorage
|
||||
{
|
||||
public:
|
||||
LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay);
|
||||
~LLSpeakersDelayActionsStorage();
|
||||
|
||||
/**
|
||||
* Sets new LLSpeakerActionTimer with passed speaker UUID.
|
||||
*/
|
||||
void setActionTimer(const LLUUID& speaker_id);
|
||||
|
||||
/**
|
||||
* Removes stored LLSpeakerActionTimer for passed speaker UUID from internal map and optionally deletes it.
|
||||
*
|
||||
* @see onTimerActionCallback()
|
||||
*/
|
||||
void unsetActionTimer(const LLUUID& speaker_id);
|
||||
|
||||
void removeAllTimers();
|
||||
private:
|
||||
/**
|
||||
* Callback of the each instance of LLSpeakerActionTimer.
|
||||
*
|
||||
* Unsets an appropriate timer instance and calls action callback for specified speacker_id.
|
||||
*
|
||||
* @see unsetActionTimer()
|
||||
*/
|
||||
bool onTimerActionCallback(const LLUUID& speaker_id);
|
||||
|
||||
LLSpeakerActionTimer::action_timers_map_t mActionTimersMap;
|
||||
LLSpeakerActionTimer::action_callback_t mActionCallback;
|
||||
|
||||
/**
|
||||
* Delay to call action callback for speakers after timer was set.
|
||||
*/
|
||||
F32 mActionDelay;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class LLSpeakerMgr : public LLOldEvents::LLObservable
|
||||
{
|
||||
LOG_CLASS(LLSpeakerMgr);
|
||||
|
||||
public:
|
||||
LLSpeakerMgr(LLVoiceChannel* channelp);
|
||||
virtual ~LLSpeakerMgr();
|
||||
|
||||
LLPointer<LLSpeaker> findSpeaker(const LLUUID& avatar_id);
|
||||
void update(BOOL resort_ok);
|
||||
void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing);
|
||||
void speakerChatted(const LLUUID& speaker_id);
|
||||
LLPointer<LLSpeaker> setSpeaker(const LLUUID& id,
|
||||
const std::string& name = LLStringUtil::null,
|
||||
LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY,
|
||||
LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT);
|
||||
|
||||
BOOL isVoiceActive();
|
||||
|
||||
typedef std::vector<LLPointer<LLSpeaker> > speaker_list_t;
|
||||
void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text);
|
||||
LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; }
|
||||
const LLUUID getSessionID();
|
||||
|
||||
/**
|
||||
* Removes avaline speaker.
|
||||
*
|
||||
* This is a HACK due to server does not send information that Avaline caller ends call.
|
||||
* It can be removed when server is updated. See EXT-4301 for details
|
||||
*/
|
||||
bool removeAvalineSpeaker(const LLUUID& speaker_id) { return removeSpeaker(speaker_id); }
|
||||
|
||||
/**
|
||||
* Initializes mVoiceModerated depend on LLSpeaker::mModeratorMutedVoice of agent's participant.
|
||||
*
|
||||
* Is used only to implement workaround to initialize mVoiceModerated on first join to group chat. See EXT-6937
|
||||
*/
|
||||
void initVoiceModerateMode();
|
||||
|
||||
protected:
|
||||
virtual void updateSpeakerList();
|
||||
void setSpeakerNotInChannel(LLSpeaker* speackerp);
|
||||
bool removeSpeaker(const LLUUID& speaker_id);
|
||||
|
||||
typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t;
|
||||
speaker_map_t mSpeakers;
|
||||
|
||||
speaker_list_t mSpeakersSorted;
|
||||
LLFrameTimer mSpeechTimer;
|
||||
LLVoiceChannel* mVoiceChannel;
|
||||
|
||||
/**
|
||||
* time out speakers when they are not part of current session
|
||||
*/
|
||||
LLSpeakersDelayActionsStorage* mSpeakerDelayRemover;
|
||||
|
||||
// *TODO: should be moved back into LLIMSpeakerMgr when a way to request the current voice channel
|
||||
// moderation mode is implemented: See EXT-6937
|
||||
bool mVoiceModerated;
|
||||
|
||||
// *TODO: To be removed when a way to request the current voice channel
|
||||
// moderation mode is implemented: See EXT-6937
|
||||
bool mModerateModeHandledFirstTime;
|
||||
};
|
||||
|
||||
class LLIMSpeakerMgr : public LLSpeakerMgr
|
||||
{
|
||||
LOG_CLASS(LLIMSpeakerMgr);
|
||||
|
||||
public:
|
||||
LLIMSpeakerMgr(LLVoiceChannel* channel);
|
||||
|
||||
void updateSpeakers(const LLSD& update);
|
||||
void setSpeakers(const LLSD& speakers);
|
||||
|
||||
void toggleAllowTextChat(const LLUUID& speaker_id);
|
||||
|
||||
/**
|
||||
* Mutes/Unmutes avatar for current group voice chat.
|
||||
*
|
||||
* It only marks avatar as muted for session and does not use local Agent's Block list.
|
||||
* It does not mute Agent itself.
|
||||
*
|
||||
* @param[in] avatar_id UUID of avatar to be processed
|
||||
* @param[in] unmute if false - specified avatar will be muted, otherwise - unmuted.
|
||||
*
|
||||
* @see moderateVoiceAllParticipants()
|
||||
*/
|
||||
void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute);
|
||||
|
||||
/**
|
||||
* Mutes/Unmutes all avatars for current group voice chat.
|
||||
*
|
||||
* It only marks avatars as muted for session and does not use local Agent's Block list.
|
||||
* It calls forceVoiceModeratedMode() in case of session is already in requested state.
|
||||
*
|
||||
* @param[in] unmute_everyone if false - avatars will be muted, otherwise - unmuted.
|
||||
*
|
||||
* @see moderateVoiceParticipant()
|
||||
*/
|
||||
void moderateVoiceAllParticipants(bool unmute_everyone);
|
||||
|
||||
void processSessionUpdate(const LLSD& session_update);
|
||||
|
||||
protected:
|
||||
virtual void updateSpeakerList();
|
||||
|
||||
void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice);
|
||||
|
||||
/**
|
||||
* Process all participants to mute/unmute them according to passed voice session state.
|
||||
*/
|
||||
void forceVoiceModeratedMode(bool should_be_muted);
|
||||
|
||||
};
|
||||
|
||||
class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr>
|
||||
{
|
||||
LOG_CLASS(LLActiveSpeakerMgr);
|
||||
|
||||
public:
|
||||
LLActiveSpeakerMgr();
|
||||
protected:
|
||||
virtual void updateSpeakerList();
|
||||
};
|
||||
|
||||
class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLLocalSpeakerMgr>
|
||||
{
|
||||
LOG_CLASS(LLLocalSpeakerMgr);
|
||||
public:
|
||||
LLLocalSpeakerMgr();
|
||||
~LLLocalSpeakerMgr ();
|
||||
protected:
|
||||
virtual void updateSpeakerList();
|
||||
};
|
||||
|
||||
#endif // LL_LLSPEAKERS_H
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
#include "llwearable.h"
|
||||
#include "llinventorybridge.h"
|
||||
#include "llappearancemgr.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "jcfloaterareasearch.h"
|
||||
#include "generichandlers.h"
|
||||
|
||||
@@ -1615,8 +1616,10 @@ bool idle_startup()
|
||||
name += " " + lastname;
|
||||
}
|
||||
gViewerWindow->getWindow()->setTitle(LLAppViewer::instance()->getWindowTitle() + "- " + name);
|
||||
// Pass the user information to the voice chat server interface.
|
||||
gVoiceClient->userAuthorized(firstname, lastname, gAgentID);
|
||||
// Pass the user information to the voice chat server interface.
|
||||
LLVoiceClient::getInstance()->userAuthorized(name, gAgentID);
|
||||
// create the default proximal channel
|
||||
LLVoiceChannel::initClass();
|
||||
LLStartUp::setStartupState( STATE_WORLD_INIT );
|
||||
}
|
||||
else
|
||||
@@ -1903,6 +1906,11 @@ bool idle_startup()
|
||||
LLStartUp::initNameCache();
|
||||
display_startup();
|
||||
|
||||
// update the voice settings *after* gCacheName initialization
|
||||
// so that we can construct voice UI that relies on the name cache
|
||||
LLVoiceClient::getInstance()->updateSettings();
|
||||
display_startup();
|
||||
|
||||
// *Note: this is where gWorldMap used to be initialized.
|
||||
|
||||
// register null callbacks for audio until the audio system is initialized
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
#include "llviewerparcelmgr.h"
|
||||
#include "llviewerthrottle.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llvoiceclient.h" // for gVoiceClient
|
||||
#include "llagentui.h"
|
||||
|
||||
#include "lltoolmgr.h"
|
||||
|
||||
@@ -182,19 +182,19 @@ void audio_update_volume(bool force_update)
|
||||
LLViewerMedia::setVolume( mute_media ? 0.0f : media_volume );
|
||||
|
||||
// Voice
|
||||
if (gVoiceClient)
|
||||
if (LLVoiceClient::instanceExists())
|
||||
{
|
||||
F32 voice_volume = mute_volume * master_volume * audio_level_voice;
|
||||
gVoiceClient->setVoiceVolume(mute_voice ? 0.f : voice_volume);
|
||||
gVoiceClient->setMicGain(mute_voice ? 0.f : audio_level_mic);
|
||||
LLVoiceClient::getInstance()->setVoiceVolume(mute_voice ? 0.f : voice_volume);
|
||||
LLVoiceClient::getInstance()->setMicGain(mute_voice ? 0.f : audio_level_mic);
|
||||
|
||||
if (!gViewerWindow->getActive() && mute_when_minimized)
|
||||
{
|
||||
gVoiceClient->setMuteMic(true);
|
||||
LLVoiceClient::getInstance()->setMuteMic(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
gVoiceClient->setMuteMic(false);
|
||||
LLVoiceClient::getInstance()->setMuteMic(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,6 +547,12 @@ bool handleEffectColorChanged(const LLSD& newvalue)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handleVoiceClientPrefsChanged(const LLSD& newvalue)
|
||||
{
|
||||
LLVoiceClient::getInstance()->updateSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handleVelocityInterpolate(const LLSD& newvalue)
|
||||
{
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
@@ -571,15 +577,6 @@ bool handleVelocityInterpolate(const LLSD& newvalue)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handleVoiceClientPrefsChanged(const LLSD& newvalue)
|
||||
{
|
||||
if(gVoiceClient)
|
||||
{
|
||||
gVoiceClient->updateSettings();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handleTranslateChatPrefsChanged(const LLSD& newvalue)
|
||||
{
|
||||
LLFloaterChat* floaterp = LLFloaterChat::getInstance();
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
#include "llstatenums.h"
|
||||
#include "llstatusbar.h"
|
||||
#include "llimview.h"
|
||||
#include "llfloateractivespeakers.h"
|
||||
#include "llspeakers.h"
|
||||
#include "lltrans.h"
|
||||
#include "llviewerfoldertype.h"
|
||||
#include "llviewergenericmessage.h"
|
||||
@@ -1320,6 +1320,14 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id,
|
||||
gNotifyBoxView->purgeMessagesMatching(OfferMatcher(blocked_id));
|
||||
}
|
||||
|
||||
LLOfferInfo::LLOfferInfo()
|
||||
: mFromGroup(FALSE)
|
||||
, mFromObject(FALSE)
|
||||
, mIM(IM_NOTHING_SPECIAL)
|
||||
, mType(LLAssetType::AT_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
LLOfferInfo::LLOfferInfo(const LLSD& sd)
|
||||
{
|
||||
mIM = (EInstantMessage)sd["im_type"].asInteger();
|
||||
@@ -1335,6 +1343,21 @@ LLOfferInfo::LLOfferInfo(const LLSD& sd)
|
||||
mHost = LLHost(sd["sender"].asString());
|
||||
}
|
||||
|
||||
LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)
|
||||
{
|
||||
mIM = info.mIM;
|
||||
mFromID = info.mFromID;
|
||||
mFromGroup = info.mFromGroup;
|
||||
mFromObject = info.mFromObject;
|
||||
mTransactionID = info.mTransactionID;
|
||||
mFolderID = info.mFolderID;
|
||||
mObjectID = info.mObjectID;
|
||||
mType = info.mType;
|
||||
mFromName = info.mFromName;
|
||||
mDesc = info.mDesc;
|
||||
mHost = info.mHost;
|
||||
}
|
||||
|
||||
LLSD LLOfferInfo::asLLSD()
|
||||
{
|
||||
LLSD sd;
|
||||
|
||||
@@ -216,11 +216,14 @@ bool highlight_offered_object(const LLUUID& obj_id);
|
||||
void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid);
|
||||
void set_dad_inbox_object(const LLUUID& object_id);
|
||||
|
||||
struct LLOfferInfo
|
||||
class LLOfferInfo
|
||||
{
|
||||
LLOfferInfo() {};
|
||||
public:
|
||||
LLOfferInfo();
|
||||
LLOfferInfo(const LLSD& sd);
|
||||
|
||||
LLOfferInfo(const LLOfferInfo& info);
|
||||
|
||||
void forceResponse(InventoryOfferResponse response);
|
||||
|
||||
EInstantMessage mIM;
|
||||
@@ -243,5 +246,3 @@ struct LLOfferInfo
|
||||
void process_feature_disabled_message(LLMessageSystem* msg, void**);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
// linden library includes
|
||||
#include "llaudioengine.h" // mute on minimize
|
||||
#include "indra_constants.h"
|
||||
#include "llassetstorage.h"
|
||||
#include "llfontgl.h"
|
||||
#include "llmousehandler.h"
|
||||
@@ -77,12 +76,9 @@
|
||||
#include "raytrace.h"
|
||||
|
||||
// newview includes
|
||||
#include "llagent.h"
|
||||
#include "llbox.h"
|
||||
#include "llchatbar.h"
|
||||
#include "llconsole.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llcylinder.h"
|
||||
#include "lldebugview.h"
|
||||
#include "lldir.h"
|
||||
#include "lldrawable.h"
|
||||
@@ -93,20 +89,11 @@
|
||||
#include "llface.h"
|
||||
#include "llfeaturemanager.h"
|
||||
#include "statemachine/aifilepicker.h"
|
||||
#include "llfloater.h"
|
||||
#include "llfloateractivespeakers.h"
|
||||
#include "llfloaterbuildoptions.h"
|
||||
#include "llfloaterbuyland.h"
|
||||
#include "llfloatercamera.h"
|
||||
#include "llfloaterchat.h"
|
||||
#include "llfloaterchatterbox.h"
|
||||
#include "llfloatercustomize.h"
|
||||
#include "llfloatereditui.h" // HACK JAMESDEBUG for ui editor
|
||||
#include "llfloaterland.h"
|
||||
#include "llfloaterinspect.h"
|
||||
#include "llfloaterinventory.h"
|
||||
#include "llfloaternamedesc.h"
|
||||
#include "llfloaterpreference.h"
|
||||
#include "llfloatersnapshot.h"
|
||||
#include "llfloaterteleporthistory.h"
|
||||
#include "llfloatertools.h"
|
||||
@@ -196,7 +183,6 @@
|
||||
#include "llnotifications.h"
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
#include "llfloatertest.h" // HACK!
|
||||
#include "llfloaternotificationsconsole.h"
|
||||
|
||||
// [RLVa:KB]
|
||||
@@ -1085,7 +1071,7 @@ BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK m
|
||||
BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
|
||||
{
|
||||
BOOL down = TRUE;
|
||||
gVoiceClient->middleMouseState(true);
|
||||
LLVoiceClient::getInstance()->middleMouseState(true);
|
||||
handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
|
||||
|
||||
// Always handled as far as the OS is concerned.
|
||||
@@ -1095,7 +1081,7 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MAS
|
||||
BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
|
||||
{
|
||||
BOOL down = FALSE;
|
||||
gVoiceClient->middleMouseState(false);
|
||||
LLVoiceClient::getInstance()->middleMouseState(false);
|
||||
handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
|
||||
|
||||
// Always handled as far as the OS is concerned.
|
||||
@@ -1237,8 +1223,7 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
|
||||
BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
|
||||
{
|
||||
// Let the voice chat code check for its PTT key. Note that this never affects event processing.
|
||||
if(gVoiceClient)
|
||||
gVoiceClient->keyDown(key, mask);
|
||||
LLVoiceClient::getInstance()->keyDown(key, mask);
|
||||
|
||||
if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
|
||||
{
|
||||
@@ -1260,7 +1245,7 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
|
||||
BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
|
||||
{
|
||||
// Let the voice chat code check for its PTT key. Note that this never affects event processing.
|
||||
gVoiceClient->keyUp(key, mask);
|
||||
LLVoiceClient::getInstance()->keyUp(key, mask);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1526,7 +1526,7 @@ void LLVOAvatar::initInstance(void)
|
||||
|
||||
//VTPause(); // VTune
|
||||
|
||||
mVoiceVisualizer->setVoiceEnabled( gVoiceClient->getVoiceEnabled( mID ) );
|
||||
mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) );
|
||||
}
|
||||
|
||||
// virtual
|
||||
@@ -2344,13 +2344,16 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
|
||||
// store off last frame's root position to be consistent with camera position
|
||||
LLVector3 root_pos_last = mRoot->getWorldPosition();
|
||||
bool detailed_update = updateCharacter(agent);
|
||||
bool voice_enabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel();
|
||||
|
||||
if (gNoRender)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
|
||||
bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) &&
|
||||
LLVoiceClient::getInstance()->getVoiceEnabled(mID);
|
||||
|
||||
idleUpdateVoiceVisualizer( voice_enabled );
|
||||
idleUpdateMisc( detailed_update );
|
||||
idleUpdateAppearanceAnimation();
|
||||
@@ -2370,10 +2373,10 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
|
||||
{
|
||||
bool render_visualizer = voice_enabled;
|
||||
|
||||
// Don't render the user's own voice visualizer when in mouselook
|
||||
// Don't render the user's own voice visualizer when in mouselook, or when opening the mic is disabled.
|
||||
if(isSelf())
|
||||
{
|
||||
if(gAgentCamera.cameraMouselook()/* || gSavedSettings.getBOOL("VoiceDisableMic")*/)
|
||||
if(gAgentCamera.cameraMouselook() || gSavedSettings.getBOOL("VoiceDisableMic"))
|
||||
{
|
||||
render_visualizer = false;
|
||||
}
|
||||
@@ -2421,7 +2424,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
|
||||
// Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been
|
||||
// "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking.
|
||||
//-----------------------------------------------------------------------------------------------------------------
|
||||
if ( gVoiceClient->getIsSpeaking( mID ) )
|
||||
if (LLVoiceClient::getInstance()->getIsSpeaking( mID ))
|
||||
{
|
||||
if ( ! mVoiceVisualizer->getCurrentlySpeaking() )
|
||||
{
|
||||
@@ -2430,7 +2433,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
|
||||
//printf( "gAwayTimer.reset();\n" );
|
||||
}
|
||||
|
||||
mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) );
|
||||
mVoiceVisualizer->setSpeakingAmplitude( LLVoiceClient::getInstance()->getCurrentPower( mID ) );
|
||||
|
||||
if( isSelf() )
|
||||
{
|
||||
@@ -2682,7 +2685,7 @@ F32 LLVOAvatar::calcMorphAmount()
|
||||
void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
|
||||
{
|
||||
// Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync
|
||||
if ( voice_enabled && (gVoiceClient->lipSyncEnabled()) && gVoiceClient->getIsSpeaking( mID ) )
|
||||
if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) )
|
||||
{
|
||||
F32 ooh_morph_amount = 0.0f;
|
||||
F32 aah_morph_amount = 0.0f;
|
||||
|
||||
966
indra/newview/llvoicechannel.cpp
Normal file
966
indra/newview/llvoicechannel.cpp
Normal file
@@ -0,0 +1,966 @@
|
||||
/**
|
||||
* @file llvoicechannel.cpp
|
||||
* @brief Voice Channel related classes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llimview.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llvoicechannel.h"
|
||||
|
||||
extern AIHTTPTimeoutPolicy voiceCallCapResponder_timeout;
|
||||
|
||||
|
||||
LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
|
||||
LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
|
||||
LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
|
||||
LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
|
||||
LLVoiceChannel::channel_changed_signal_t LLVoiceChannel::sCurrentVoiceChannelChangedSignal;
|
||||
|
||||
BOOL LLVoiceChannel::sSuspended = FALSE;
|
||||
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
const U32 DEFAULT_RETRIES_COUNT = 3;
|
||||
|
||||
|
||||
class LLVoiceCallCapResponder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {};
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason); // called with bad status codes
|
||||
/*virtual*/ void result(const LLSD& content);
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return voiceCallCapResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "LLVoiceCallCapResponder"; }
|
||||
|
||||
private:
|
||||
LLUUID mSessionID;
|
||||
};
|
||||
|
||||
|
||||
void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
|
||||
{
|
||||
LL_WARNS("Voice") << "LLVoiceCallCapResponder error [status:"
|
||||
<< status << "]: " << reason << LL_ENDL;
|
||||
LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
|
||||
if ( channelp )
|
||||
{
|
||||
if ( 403 == status )
|
||||
{
|
||||
//403 == no ability
|
||||
LLNotificationsUtil::add(
|
||||
"VoiceNotAllowed",
|
||||
channelp->getNotifyArgs());
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add(
|
||||
"VoiceCallGenericError",
|
||||
channelp->getNotifyArgs());
|
||||
}
|
||||
channelp->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceCallCapResponder::result(const LLSD& content)
|
||||
{
|
||||
LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
|
||||
if (channelp)
|
||||
{
|
||||
// *TODO: DEBUG SPAM
|
||||
LLSD::map_const_iterator iter;
|
||||
for(iter = content.beginMap(); iter != content.endMap(); ++iter)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got "
|
||||
<< iter->first << LL_ENDL;
|
||||
}
|
||||
|
||||
channelp->setChannelInfo(
|
||||
content["voice_credentials"]["channel_uri"].asString(),
|
||||
content["voice_credentials"]["channel_credentials"].asString());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLVoiceChannel
|
||||
//
|
||||
LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :
|
||||
mSessionID(session_id),
|
||||
mState(STATE_NO_CHANNEL_INFO),
|
||||
mSessionName(session_name),
|
||||
mCallDirection(OUTGOING_CALL),
|
||||
mIgnoreNextSessionLeave(FALSE),
|
||||
mCallEndedByAgent(false)
|
||||
{
|
||||
mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName;
|
||||
|
||||
if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second)
|
||||
{
|
||||
// a voice channel already exists for this session id, so this instance will be orphaned
|
||||
// the end result should simply be the failure to make voice calls
|
||||
LL_WARNS("Voice") << "Duplicate voice channels registered for session_id " << session_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
LLVoiceChannel::~LLVoiceChannel()
|
||||
{
|
||||
// Must check instance exists here, the singleton MAY have already been destroyed.
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceClient::getInstance()->removeObserver(this);
|
||||
}
|
||||
|
||||
sVoiceChannelMap.erase(mSessionID);
|
||||
sVoiceChannelURIMap.erase(mURI);
|
||||
}
|
||||
|
||||
void LLVoiceChannel::setChannelInfo(
|
||||
const std::string& uri,
|
||||
const std::string& credentials)
|
||||
{
|
||||
setURI(uri);
|
||||
|
||||
mCredentials = credentials;
|
||||
|
||||
if (mState == STATE_NO_CHANNEL_INFO)
|
||||
{
|
||||
if (mURI.empty())
|
||||
{
|
||||
LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
|
||||
LL_WARNS("Voice") << "Received empty URI for channel " << mSessionName << LL_ENDL;
|
||||
deactivate();
|
||||
}
|
||||
else if (mCredentials.empty())
|
||||
{
|
||||
LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
|
||||
LL_WARNS("Voice") << "Received empty credentials for channel " << mSessionName << LL_ENDL;
|
||||
deactivate();
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(STATE_READY);
|
||||
|
||||
// if we are supposed to be active, reconnect
|
||||
// this will happen on initial connect, as we request credentials on first use
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
// just in case we got new channel info while active
|
||||
// should move over to new channel
|
||||
activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal)
|
||||
{
|
||||
if (channelURI != mURI)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type < BEGIN_ERROR_STATUS)
|
||||
{
|
||||
handleStatusChange(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
handleError(type);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannel::handleStatusChange(EStatusType type)
|
||||
{
|
||||
// status updates
|
||||
switch(type)
|
||||
{
|
||||
case STATUS_LOGIN_RETRY:
|
||||
//mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle();
|
||||
LLNotificationsUtil::add("VoiceLoginRetry");
|
||||
break;
|
||||
case STATUS_LOGGED_IN:
|
||||
//if (!mLoginNotificationHandle.isDead())
|
||||
//{
|
||||
// LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get();
|
||||
// if (notifyp)
|
||||
// {
|
||||
// notifyp->close();
|
||||
// }
|
||||
// mLoginNotificationHandle.markDead();
|
||||
//}
|
||||
break;
|
||||
case STATUS_LEFT_CHANNEL:
|
||||
if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
|
||||
{
|
||||
// if forceably removed from channel
|
||||
// update the UI and revert to default channel
|
||||
LLNotificationsUtil::add("VoiceChannelDisconnected", mNotifyArgs);
|
||||
deactivate();
|
||||
}
|
||||
mIgnoreNextSessionLeave = FALSE;
|
||||
break;
|
||||
case STATUS_JOINING:
|
||||
if (callStarted())
|
||||
{
|
||||
setState(STATE_RINGING);
|
||||
}
|
||||
break;
|
||||
case STATUS_JOINED:
|
||||
if (callStarted())
|
||||
{
|
||||
setState(STATE_CONNECTED);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// default behavior is to just deactivate channel
|
||||
// derived classes provide specific error messages
|
||||
void LLVoiceChannel::handleError(EStatusType type)
|
||||
{
|
||||
deactivate();
|
||||
setState(STATE_ERROR);
|
||||
}
|
||||
|
||||
BOOL LLVoiceChannel::isActive()
|
||||
{
|
||||
// only considered active when currently bound channel matches what our channel
|
||||
return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;
|
||||
}
|
||||
|
||||
BOOL LLVoiceChannel::callStarted()
|
||||
{
|
||||
return mState >= STATE_CALL_STARTED;
|
||||
}
|
||||
|
||||
void LLVoiceChannel::deactivate()
|
||||
{
|
||||
if (mState >= STATE_RINGING)
|
||||
{
|
||||
// ignore session leave event
|
||||
mIgnoreNextSessionLeave = TRUE;
|
||||
}
|
||||
|
||||
if (callStarted())
|
||||
{
|
||||
setState(STATE_HUNG_UP);
|
||||
|
||||
//Default mic is OFF when leaving voice calls
|
||||
if (gSavedSettings.getBOOL("AutoDisengageMic") &&
|
||||
sCurrentVoiceChannel == this &&
|
||||
LLVoiceClient::getInstance()->getUserPTTState())
|
||||
{
|
||||
gSavedSettings.setBOOL("PTTCurrentlyEnabled", true);
|
||||
LLVoiceClient::getInstance()->inputUserControlState(true);
|
||||
}
|
||||
}
|
||||
LLVoiceClient::getInstance()->removeObserver(this);
|
||||
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
// default channel is proximal channel
|
||||
sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
|
||||
sCurrentVoiceChannel->activate();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannel::activate()
|
||||
{
|
||||
if (callStarted())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// deactivate old channel and mark ourselves as the active one
|
||||
if (sCurrentVoiceChannel != this)
|
||||
{
|
||||
// mark as current before deactivating the old channel to prevent
|
||||
// activating the proximal channel between IM calls
|
||||
LLVoiceChannel* old_channel = sCurrentVoiceChannel;
|
||||
sCurrentVoiceChannel = this;
|
||||
//mCallDialogPayload["old_channel_name"] = "";
|
||||
if (old_channel)
|
||||
{
|
||||
//mCallDialogPayload["old_channel_name"] = old_channel->getSessionName();
|
||||
old_channel->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
if (mState == STATE_NO_CHANNEL_INFO)
|
||||
{
|
||||
// responsible for setting status to active
|
||||
getChannelInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(STATE_CALL_STARTED);
|
||||
}
|
||||
|
||||
LLVoiceClient::getInstance()->addObserver(this);
|
||||
|
||||
//do not send earlier, channel should be initialized, should not be in STATE_NO_CHANNEL_INFO state
|
||||
sCurrentVoiceChannelChangedSignal(this->mSessionID);
|
||||
}
|
||||
|
||||
void LLVoiceChannel::getChannelInfo()
|
||||
{
|
||||
// pretend we have everything we need
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
setState(STATE_CALL_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id)
|
||||
{
|
||||
voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id);
|
||||
if (found_it == sVoiceChannelMap.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return found_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)
|
||||
{
|
||||
voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri);
|
||||
if (found_it == sVoiceChannelURIMap.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return found_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
LLVoiceChannel* LLVoiceChannel::getCurrentVoiceChannel()
|
||||
{
|
||||
return sCurrentVoiceChannel;
|
||||
}
|
||||
|
||||
void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
|
||||
{
|
||||
sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
|
||||
mSessionID = new_session_id;
|
||||
sVoiceChannelMap.insert(std::make_pair(mSessionID, this));
|
||||
}
|
||||
|
||||
void LLVoiceChannel::setURI(std::string uri)
|
||||
{
|
||||
sVoiceChannelURIMap.erase(mURI);
|
||||
mURI = uri;
|
||||
sVoiceChannelURIMap.insert(std::make_pair(mURI, this));
|
||||
}
|
||||
|
||||
void LLVoiceChannel::setState(EState state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case STATE_RINGING:
|
||||
gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
|
||||
break;
|
||||
case STATE_CONNECTED:
|
||||
gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs);
|
||||
break;
|
||||
case STATE_HUNG_UP:
|
||||
gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
doSetState(state);
|
||||
}
|
||||
|
||||
void LLVoiceChannel::doSetState(const EState& new_state)
|
||||
{
|
||||
EState old_state = mState;
|
||||
mState = new_state;
|
||||
|
||||
if (!mStateChangedCallback.empty())
|
||||
mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVoiceChannel::initClass()
|
||||
{
|
||||
sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVoiceChannel::suspend()
|
||||
{
|
||||
if (!sSuspended)
|
||||
{
|
||||
sSuspendedVoiceChannel = sCurrentVoiceChannel;
|
||||
sSuspended = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVoiceChannel::resume()
|
||||
{
|
||||
if (sSuspended)
|
||||
{
|
||||
if (LLVoiceClient::getInstance()->voiceEnabled())
|
||||
{
|
||||
if (sSuspendedVoiceChannel)
|
||||
{
|
||||
sSuspendedVoiceChannel->activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVoiceChannelProximal::getInstance()->activate();
|
||||
}
|
||||
}
|
||||
sSuspended = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
boost::signals2::connection LLVoiceChannel::setCurrentVoiceChannelChangedCallback(channel_changed_callback_t cb, bool at_front)
|
||||
{
|
||||
if (at_front)
|
||||
{
|
||||
return sCurrentVoiceChannelChangedSignal.connect(cb, boost::signals2::at_front);
|
||||
}
|
||||
else
|
||||
{
|
||||
return sCurrentVoiceChannelChangedSignal.connect(cb);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLVoiceChannelGroup
|
||||
//
|
||||
|
||||
LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :
|
||||
LLVoiceChannel(session_id, session_name)
|
||||
{
|
||||
mRetries = DEFAULT_RETRIES_COUNT;
|
||||
mIsRetrying = FALSE;
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::deactivate()
|
||||
{
|
||||
if (callStarted())
|
||||
{
|
||||
LLVoiceClient::getInstance()->leaveNonSpatialChannel();
|
||||
}
|
||||
LLVoiceChannel::deactivate();
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::activate()
|
||||
{
|
||||
if (callStarted()) return;
|
||||
|
||||
LLVoiceChannel::activate();
|
||||
|
||||
if (callStarted())
|
||||
{
|
||||
// we have the channel info, just need to use it now
|
||||
LLVoiceClient::getInstance()->setNonSpatialChannel(
|
||||
mURI,
|
||||
mCredentials);
|
||||
|
||||
/*
|
||||
if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel
|
||||
{
|
||||
LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionID);
|
||||
// Adding ad-hoc call participants to Recent People List.
|
||||
// If it's an outgoing ad-hoc, we can use mInitialTargetIDs that holds IDs of people we
|
||||
// called(both online and offline) as source to get people for recent (STORM-210).
|
||||
if (session->isOutgoingAdHoc())
|
||||
{
|
||||
for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();
|
||||
it!=session->mInitialTargetIDs.end();++it)
|
||||
{
|
||||
const LLUUID id = *it;
|
||||
LLRecentPeople::instance().add(id);
|
||||
}
|
||||
}
|
||||
// If this ad-hoc is incoming then trying to get ids of people from mInitialTargetIDs
|
||||
// would lead to EXT-8246. So in this case we get them from speakers list.
|
||||
else
|
||||
{
|
||||
LLIMModel::addSpeakersToRecent(mSessionID);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//Mic default state is OFF on initiating/joining Ad-Hoc/Group calls
|
||||
if (LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle())
|
||||
{
|
||||
LLVoiceClient::getInstance()->inputUserControlState(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::getChannelInfo()
|
||||
{
|
||||
LLViewerRegion* region = gAgent.getRegion();
|
||||
if (region)
|
||||
{
|
||||
std::string url = region->getCapability("ChatSessionRequest");
|
||||
LLSD data;
|
||||
data["method"] = "call";
|
||||
data["session-id"] = mSessionID;
|
||||
LLHTTPClient::post(url,
|
||||
data,
|
||||
new LLVoiceCallCapResponder(mSessionID));
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::setChannelInfo(
|
||||
const std::string& uri,
|
||||
const std::string& credentials)
|
||||
{
|
||||
setURI(uri);
|
||||
|
||||
mCredentials = credentials;
|
||||
|
||||
if (mState == STATE_NO_CHANNEL_INFO)
|
||||
{
|
||||
if(!mURI.empty() && !mCredentials.empty())
|
||||
{
|
||||
setState(STATE_READY);
|
||||
|
||||
// if we are supposed to be active, reconnect
|
||||
// this will happen on initial connect, as we request credentials on first use
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
// just in case we got new channel info while active
|
||||
// should move over to new channel
|
||||
activate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//*TODO: notify user
|
||||
LL_WARNS("Voice") << "Received invalid credentials for channel " << mSessionName << LL_ENDL;
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
else if ( mIsRetrying )
|
||||
{
|
||||
// we have the channel info, just need to use it now
|
||||
LLVoiceClient::getInstance()->setNonSpatialChannel(
|
||||
mURI,
|
||||
mCredentials);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::handleStatusChange(EStatusType type)
|
||||
{
|
||||
// status updates
|
||||
switch(type)
|
||||
{
|
||||
case STATUS_JOINED:
|
||||
mRetries = 3;
|
||||
mIsRetrying = FALSE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleStatusChange(type);
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::handleError(EStatusType status)
|
||||
{
|
||||
std::string notify;
|
||||
switch(status)
|
||||
{
|
||||
case ERROR_CHANNEL_LOCKED:
|
||||
case ERROR_CHANNEL_FULL:
|
||||
notify = "VoiceChannelFull";
|
||||
break;
|
||||
case ERROR_NOT_AVAILABLE:
|
||||
//clear URI and credentials
|
||||
//set the state to be no info
|
||||
//and activate
|
||||
if ( mRetries > 0 )
|
||||
{
|
||||
mRetries--;
|
||||
mIsRetrying = TRUE;
|
||||
mIgnoreNextSessionLeave = TRUE;
|
||||
|
||||
getChannelInfo();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
notify = "VoiceChannelJoinFailed";
|
||||
mRetries = DEFAULT_RETRIES_COUNT;
|
||||
mIsRetrying = FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ERROR_UNKNOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// notification
|
||||
if (!notify.empty())
|
||||
{
|
||||
LLNotificationPtr notification = LLNotificationsUtil::add(notify, mNotifyArgs);
|
||||
// echo to im window
|
||||
gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage());
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleError(status);
|
||||
}
|
||||
|
||||
void LLVoiceChannelGroup::setState(EState state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case STATE_RINGING:
|
||||
if ( !mIsRetrying )
|
||||
{
|
||||
gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
|
||||
}
|
||||
|
||||
doSetState(state);
|
||||
break;
|
||||
default:
|
||||
LLVoiceChannel::setState(state);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLVoiceChannelProximal
|
||||
//
|
||||
LLVoiceChannelProximal::LLVoiceChannelProximal() :
|
||||
LLVoiceChannel(LLUUID::null, LLStringUtil::null)
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLVoiceChannelProximal::isActive()
|
||||
{
|
||||
return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();
|
||||
}
|
||||
|
||||
void LLVoiceChannelProximal::activate()
|
||||
{
|
||||
if (callStarted()) return;
|
||||
|
||||
if((LLVoiceChannel::sCurrentVoiceChannel != this) && (LLVoiceChannel::getState() == STATE_CONNECTED))
|
||||
{
|
||||
// we're connected to a non-spatial channel, so disconnect.
|
||||
LLVoiceClient::getInstance()->leaveNonSpatialChannel();
|
||||
}
|
||||
LLVoiceChannel::activate();
|
||||
|
||||
}
|
||||
|
||||
void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal)
|
||||
{
|
||||
if (!proximal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type < BEGIN_ERROR_STATUS)
|
||||
{
|
||||
handleStatusChange(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
handleError(type);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
|
||||
{
|
||||
// status updates
|
||||
switch(status)
|
||||
{
|
||||
case STATUS_LEFT_CHANNEL:
|
||||
// do not notify user when leaving proximal channel
|
||||
return;
|
||||
case STATUS_VOICE_DISABLED:
|
||||
//skip showing "Voice not available at your current location" when agent voice is disabled (EXT-4749)
|
||||
if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking())
|
||||
{
|
||||
gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LLVoiceChannel::handleStatusChange(status);
|
||||
}
|
||||
|
||||
|
||||
void LLVoiceChannelProximal::handleError(EStatusType status)
|
||||
{
|
||||
std::string notify;
|
||||
switch(status)
|
||||
{
|
||||
case ERROR_CHANNEL_LOCKED:
|
||||
case ERROR_CHANNEL_FULL:
|
||||
notify = "ProximalVoiceChannelFull";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// notification
|
||||
if (!notify.empty())
|
||||
{
|
||||
LLNotificationsUtil::add(notify, mNotifyArgs);
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleError(status);
|
||||
}
|
||||
|
||||
void LLVoiceChannelProximal::deactivate()
|
||||
{
|
||||
if (callStarted())
|
||||
{
|
||||
setState(STATE_HUNG_UP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLVoiceChannelP2P
|
||||
//
|
||||
LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :
|
||||
LLVoiceChannelGroup(session_id, session_name),
|
||||
mOtherUserID(other_user_id),
|
||||
mReceivedCall(FALSE)
|
||||
{
|
||||
// make sure URI reflects encoded version of other user's agent id
|
||||
// *NOTE: in case of Avaline call generated SIP URL will be incorrect.
|
||||
// But it will be overridden in LLVoiceChannelP2P::setSessionHandle() called when agent accepts call
|
||||
setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
|
||||
{
|
||||
LL_INFOS("Voice") << "P2P CALL CHANNEL STATUS CHANGE: incoming=" << int(mReceivedCall) << " newstatus=" << LLVoiceClientStatusObserver::status2string(type) << " (mState=" << mState << ")" << LL_ENDL;
|
||||
|
||||
// status updates
|
||||
switch(type)
|
||||
{
|
||||
case STATUS_LEFT_CHANNEL:
|
||||
if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
|
||||
{
|
||||
// *TODO: use it to show DECLINE voice notification
|
||||
if (mState == STATE_RINGING)
|
||||
{
|
||||
// other user declined call
|
||||
LLNotificationsUtil::add("P2PCallDeclined", mNotifyArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// other user hung up, so we didn't end the call
|
||||
LLNotificationsUtil::add("VoiceChannelDisconnectedP2P", mNotifyArgs);
|
||||
mCallEndedByAgent = false;
|
||||
}
|
||||
deactivate();
|
||||
}
|
||||
mIgnoreNextSessionLeave = FALSE;
|
||||
return;
|
||||
case STATUS_JOINING:
|
||||
// because we join session we expect to process session leave event in the future. EXT-7371
|
||||
// may be this should be done in the LLVoiceChannel::handleStatusChange.
|
||||
mIgnoreNextSessionLeave = FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleStatusChange(type);
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::handleError(EStatusType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ERROR_NOT_AVAILABLE:
|
||||
LLNotificationsUtil::add("P2PCallNoAnswer", mNotifyArgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LLVoiceChannel::handleError(type);
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::activate()
|
||||
{
|
||||
if (callStarted()) return;
|
||||
|
||||
//call will be counted as ended by user unless this variable is changed in handleStatusChange()
|
||||
mCallEndedByAgent = true;
|
||||
|
||||
LLVoiceChannel::activate();
|
||||
|
||||
if (callStarted())
|
||||
{
|
||||
// no session handle yet, we're starting the call
|
||||
if (mSessionHandle.empty())
|
||||
{
|
||||
mReceivedCall = FALSE;
|
||||
LLVoiceClient::getInstance()->callUser(mOtherUserID);
|
||||
}
|
||||
// otherwise answering the call
|
||||
else
|
||||
{
|
||||
if (!LLVoiceClient::getInstance()->answerInvite(mSessionHandle))
|
||||
{
|
||||
mCallEndedByAgent = false;
|
||||
mSessionHandle.clear();
|
||||
handleError(ERROR_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
// using the session handle invalidates it. Clear it out here so we can't reuse it by accident.
|
||||
mSessionHandle.clear();
|
||||
}
|
||||
|
||||
// Add the party to the list of people with which we've recently interacted.
|
||||
//addToTheRecentPeopleList();
|
||||
|
||||
//Default mic is ON on initiating/joining P2P calls
|
||||
if (!LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle())
|
||||
{
|
||||
LLVoiceClient::getInstance()->inputUserControlState(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::getChannelInfo()
|
||||
{
|
||||
// pretend we have everything we need, since P2P doesn't use channel info
|
||||
if (sCurrentVoiceChannel == this)
|
||||
{
|
||||
setState(STATE_CALL_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
// receiving session from other user who initiated call
|
||||
void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI)
|
||||
{
|
||||
BOOL needs_activate = FALSE;
|
||||
if (callStarted())
|
||||
{
|
||||
// defer to lower agent id when already active
|
||||
if (mOtherUserID < gAgent.getID())
|
||||
{
|
||||
// pretend we haven't started the call yet, so we can connect to this session instead
|
||||
deactivate();
|
||||
needs_activate = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are active and have priority, invite the other user again
|
||||
// under the assumption they will join this new session
|
||||
mSessionHandle.clear();
|
||||
LLVoiceClient::getInstance()->callUser(mOtherUserID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mSessionHandle = handle;
|
||||
|
||||
// The URI of a p2p session should always be the other end's SIP URI.
|
||||
if(!inURI.empty())
|
||||
{
|
||||
setURI(inURI);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Voice") << "incoming SIP URL is not provided. Channel may not work properly." << LL_ENDL;
|
||||
// In the case of an incoming AvaLine call, the generated URI will be different from the
|
||||
// original one. This is because the P2P URI is based on avatar UUID but Avaline is not.
|
||||
// See LLVoiceClient::sessionAddedEvent()
|
||||
setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
|
||||
}
|
||||
|
||||
mReceivedCall = TRUE;
|
||||
|
||||
if (needs_activate)
|
||||
{
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVoiceChannelP2P::setState(EState state)
|
||||
{
|
||||
LL_INFOS("Voice") << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << LL_ENDL;
|
||||
|
||||
if (mReceivedCall) // incoming call
|
||||
{
|
||||
// you only "answer" voice invites in p2p mode
|
||||
// so provide a special purpose message here
|
||||
if (mReceivedCall && state == STATE_RINGING)
|
||||
{
|
||||
gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs);
|
||||
doSetState(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LLVoiceChannel::setState(state);
|
||||
}
|
||||
|
||||
/*void LLVoiceChannelP2P::addToTheRecentPeopleList()
|
||||
{
|
||||
bool avaline_call = LLIMModel::getInstance()->findIMSession(mSessionID)->isAvalineSessionType();
|
||||
|
||||
if (avaline_call)
|
||||
{
|
||||
LLSD call_data;
|
||||
std::string call_number = LLVoiceChannel::getSessionName();
|
||||
|
||||
call_data["avaline_call"] = true;
|
||||
call_data["session_id"] = mSessionID;
|
||||
call_data["call_number"] = call_number;
|
||||
call_data["date"] = LLDate::now();
|
||||
|
||||
LLRecentPeople::instance().add(mOtherUserID, call_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLRecentPeople::instance().add(mOtherUserID);
|
||||
}
|
||||
}*/
|
||||
|
||||
205
indra/newview/llvoicechannel.h
Normal file
205
indra/newview/llvoicechannel.h
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @file llvoicechannel.h
|
||||
* @brief Voice channel related classes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_VOICECHANNEL_H
|
||||
#define LL_VOICECHANNEL_H
|
||||
|
||||
#include "llvoiceclient.h"
|
||||
|
||||
class LLVoiceChannel : public LLVoiceClientStatusObserver
|
||||
{
|
||||
public:
|
||||
typedef enum e_voice_channel_state
|
||||
{
|
||||
STATE_NO_CHANNEL_INFO,
|
||||
STATE_ERROR,
|
||||
STATE_HUNG_UP,
|
||||
STATE_READY,
|
||||
STATE_CALL_STARTED,
|
||||
STATE_RINGING,
|
||||
STATE_CONNECTED
|
||||
} EState;
|
||||
|
||||
typedef enum e_voice_channel_direction
|
||||
{
|
||||
INCOMING_CALL,
|
||||
OUTGOING_CALL
|
||||
} EDirection;
|
||||
|
||||
typedef boost::signals2::signal<void(const EState& old_state, const EState& new_state, const EDirection& direction, bool ended_by_agent)> state_changed_signal_t;
|
||||
|
||||
// on current channel changed signal
|
||||
typedef boost::function<void(const LLUUID& session_id)> channel_changed_callback_t;
|
||||
typedef boost::signals2::signal<void(const LLUUID& session_id)> channel_changed_signal_t;
|
||||
static channel_changed_signal_t sCurrentVoiceChannelChangedSignal;
|
||||
static boost::signals2::connection setCurrentVoiceChannelChangedCallback(channel_changed_callback_t cb, bool at_front = false);
|
||||
|
||||
|
||||
|
||||
LLVoiceChannel(const LLUUID& session_id, const std::string& session_name);
|
||||
virtual ~LLVoiceChannel();
|
||||
|
||||
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
|
||||
|
||||
virtual void handleStatusChange(EStatusType status);
|
||||
virtual void handleError(EStatusType status);
|
||||
virtual void deactivate();
|
||||
virtual void activate();
|
||||
virtual void setChannelInfo(
|
||||
const std::string& uri,
|
||||
const std::string& credentials);
|
||||
virtual void getChannelInfo();
|
||||
virtual BOOL isActive();
|
||||
virtual BOOL callStarted();
|
||||
|
||||
// Session name is a UI label used for feedback about which person,
|
||||
// group, or phone number you are talking to
|
||||
const std::string& getSessionName() const { return mSessionName; }
|
||||
|
||||
boost::signals2::connection setStateChangedCallback(const state_changed_signal_t::slot_type& callback)
|
||||
{ return mStateChangedCallback.connect(callback); }
|
||||
|
||||
const LLUUID getSessionID() { return mSessionID; }
|
||||
EState getState() { return mState; }
|
||||
|
||||
void updateSessionID(const LLUUID& new_session_id);
|
||||
const LLSD& getNotifyArgs() { return mNotifyArgs; }
|
||||
|
||||
void setCallDirection(EDirection direction) {mCallDirection = direction;}
|
||||
EDirection getCallDirection() {return mCallDirection;}
|
||||
|
||||
static LLVoiceChannel* getChannelByID(const LLUUID& session_id);
|
||||
static LLVoiceChannel* getChannelByURI(std::string uri);
|
||||
static LLVoiceChannel* getCurrentVoiceChannel();
|
||||
|
||||
static void initClass();
|
||||
|
||||
static void suspend();
|
||||
static void resume();
|
||||
|
||||
protected:
|
||||
virtual void setState(EState state);
|
||||
/**
|
||||
* Use this method if you want mStateChangedCallback to be executed while state is changed
|
||||
*/
|
||||
void doSetState(const EState& state);
|
||||
void setURI(std::string uri);
|
||||
|
||||
// there can be two directions INCOMING and OUTGOING
|
||||
EDirection mCallDirection;
|
||||
|
||||
std::string mURI;
|
||||
std::string mCredentials;
|
||||
LLUUID mSessionID;
|
||||
EState mState;
|
||||
std::string mSessionName;
|
||||
LLSD mNotifyArgs;
|
||||
//LLSD mCallDialogPayload;
|
||||
// true if call was ended by agent
|
||||
bool mCallEndedByAgent;
|
||||
BOOL mIgnoreNextSessionLeave;
|
||||
LLHandle<LLPanel> mLoginNotificationHandle;
|
||||
|
||||
typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t;
|
||||
static voice_channel_map_t sVoiceChannelMap;
|
||||
|
||||
typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t;
|
||||
static voice_channel_map_uri_t sVoiceChannelURIMap;
|
||||
|
||||
static LLVoiceChannel* sCurrentVoiceChannel;
|
||||
static LLVoiceChannel* sSuspendedVoiceChannel;
|
||||
static BOOL sSuspended;
|
||||
|
||||
private:
|
||||
state_changed_signal_t mStateChangedCallback;
|
||||
};
|
||||
|
||||
class LLVoiceChannelGroup : public LLVoiceChannel
|
||||
{
|
||||
public:
|
||||
LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name);
|
||||
|
||||
/*virtual*/ void handleStatusChange(EStatusType status);
|
||||
/*virtual*/ void handleError(EStatusType status);
|
||||
/*virtual*/ void activate();
|
||||
/*virtual*/ void deactivate();
|
||||
/*vritual*/ void setChannelInfo(
|
||||
const std::string& uri,
|
||||
const std::string& credentials);
|
||||
/*virtual*/ void getChannelInfo();
|
||||
|
||||
protected:
|
||||
virtual void setState(EState state);
|
||||
|
||||
private:
|
||||
U32 mRetries;
|
||||
BOOL mIsRetrying;
|
||||
};
|
||||
|
||||
class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal>
|
||||
{
|
||||
public:
|
||||
LLVoiceChannelProximal();
|
||||
|
||||
/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
|
||||
/*virtual*/ void handleStatusChange(EStatusType status);
|
||||
/*virtual*/ void handleError(EStatusType status);
|
||||
/*virtual*/ BOOL isActive();
|
||||
/*virtual*/ void activate();
|
||||
/*virtual*/ void deactivate();
|
||||
|
||||
};
|
||||
|
||||
class LLVoiceChannelP2P : public LLVoiceChannelGroup
|
||||
{
|
||||
public:
|
||||
LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id);
|
||||
|
||||
/*virtual*/ void handleStatusChange(EStatusType status);
|
||||
/*virtual*/ void handleError(EStatusType status);
|
||||
/*virtual*/ void activate();
|
||||
/*virtual*/ void getChannelInfo();
|
||||
|
||||
void setSessionHandle(const std::string& handle, const std::string &inURI);
|
||||
|
||||
protected:
|
||||
virtual void setState(EState state);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Add the caller to the list of people with which we've recently interacted
|
||||
*
|
||||
void addToTheRecentPeopleList();
|
||||
**/
|
||||
|
||||
std::string mSessionHandle;
|
||||
LLUUID mOtherUserID;
|
||||
BOOL mReceivedCall;
|
||||
};
|
||||
|
||||
#endif // LL_VOICECHANNEL_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -37,9 +37,8 @@
|
||||
#include "llui.h"
|
||||
#include "llbutton.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "llvoiceclient.h"
|
||||
#include "llimpanel.h"
|
||||
#include "llfloateractivespeakers.h"
|
||||
#include "llfloaterchatterbox.h"
|
||||
#include "lliconctrl.h"
|
||||
@@ -114,15 +113,15 @@ void LLVoiceRemoteCtrl::draw()
|
||||
if (!mTalkBtn->hasMouseCapture())
|
||||
{
|
||||
// not in push to talk mode, or push to talk is active means I'm talking
|
||||
mTalkBtn->setToggleState(!ptt_currently_enabled || gVoiceClient->getUserPTTState());
|
||||
mTalkBtn->setToggleState(!ptt_currently_enabled || LLVoiceClient::getInstance()->getUserPTTState());
|
||||
}
|
||||
mSpeakersBtn->setToggleState(LLFloaterActiveSpeakers::instanceVisible(LLSD()));
|
||||
mTalkLockBtn->setToggleState(!ptt_currently_enabled);
|
||||
|
||||
std::string talk_blip_image;
|
||||
if (gVoiceClient->getIsSpeaking(gAgent.getID()))
|
||||
if (LLVoiceClient::getInstance()->getIsSpeaking(gAgent.getID()))
|
||||
{
|
||||
F32 voice_power = gVoiceClient->getCurrentPower(gAgent.getID());
|
||||
F32 voice_power = LLVoiceClient::getInstance()->getCurrentPower(gAgent.getID());
|
||||
|
||||
if (voice_power > LLVoiceClient::OVERDRIVEN_POWER_LEVEL)
|
||||
{
|
||||
@@ -130,7 +129,7 @@ void LLVoiceRemoteCtrl::draw()
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 power = gVoiceClient->getCurrentPower(gAgent.getID());
|
||||
F32 power = LLVoiceClient::getInstance()->getCurrentPower(gAgent.getID());
|
||||
S32 icon_image_idx = llmin(2, llfloor((power / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f));
|
||||
|
||||
switch(icon_image_idx)
|
||||
@@ -159,15 +158,19 @@ void LLVoiceRemoteCtrl::draw()
|
||||
}
|
||||
|
||||
LLFloater* voice_floater = LLFloaterChatterBox::getInstance()->getCurrentVoiceFloater();
|
||||
LLVoiceChannel* current_channel = LLVoiceChannel::getCurrentVoiceChannel();
|
||||
if (!voice_floater) // Maybe it's undocked
|
||||
{
|
||||
voice_floater = gIMMgr->findFloaterBySession(current_channel->getSessionID());
|
||||
}
|
||||
std::string active_channel_name;
|
||||
if (voice_floater)
|
||||
{
|
||||
active_channel_name = voice_floater->getShortTitle();
|
||||
}
|
||||
|
||||
LLVoiceChannel* current_channel = LLVoiceChannel::getCurrentVoiceChannel();
|
||||
if (LLButton* end_call_btn = findChild<LLButton>("end_call_btn"))
|
||||
end_call_btn->setEnabled(LLVoiceClient::voiceEnabled()
|
||||
end_call_btn->setEnabled(LLVoiceClient::getInstance()->voiceEnabled()
|
||||
&& current_channel
|
||||
&& current_channel->isActive()
|
||||
&& current_channel != LLVoiceChannelProximal::getInstance());
|
||||
@@ -225,7 +228,7 @@ void LLVoiceRemoteCtrl::onBtnTalkClicked()
|
||||
// when in toggle mode, clicking talk button turns mic on/off
|
||||
if (gSavedSettings.getBOOL("PushToTalkToggle"))
|
||||
{
|
||||
gVoiceClient->toggleUserPTTState();
|
||||
LLVoiceClient::getInstance()->toggleUserPTTState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +237,7 @@ void LLVoiceRemoteCtrl::onBtnTalkHeld()
|
||||
// when not in toggle mode, holding down talk button turns on mic
|
||||
if (!gSavedSettings.getBOOL("PushToTalkToggle"))
|
||||
{
|
||||
gVoiceClient->setUserPTTState(true);
|
||||
LLVoiceClient::getInstance()->setUserPTTState(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +246,7 @@ void LLVoiceRemoteCtrl::onBtnTalkReleased()
|
||||
// when not in toggle mode, releasing talk button turns off mic
|
||||
if (!gSavedSettings.getBOOL("PushToTalkToggle"))
|
||||
{
|
||||
gVoiceClient->setUserPTTState(false);
|
||||
LLVoiceClient::getInstance()->setUserPTTState(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,5 +294,16 @@ void LLVoiceRemoteCtrl::onClickSpeakers()
|
||||
//static
|
||||
void LLVoiceRemoteCtrl::onClickVoiceChannel()
|
||||
{
|
||||
LLFloaterChatterBox::showInstance();
|
||||
if (LLFloater* floater = LLFloaterChatterBox::getInstance()->getCurrentVoiceFloater())
|
||||
{
|
||||
if (LLMultiFloater* mf = floater->getHost()) // Docked
|
||||
mf->showFloater(floater);
|
||||
else // Probably only local chat
|
||||
floater->open();
|
||||
}
|
||||
else if (LLVoiceChannel* chan = LLVoiceChannel::getCurrentVoiceChannel()) // Detached chat floater
|
||||
{
|
||||
if (LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(chan->getSessionID()))
|
||||
floater->open();
|
||||
}
|
||||
}
|
||||
|
||||
7844
indra/newview/llvoicevivox.cpp
Normal file
7844
indra/newview/llvoicevivox.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1016
indra/newview/llvoicevivox.h
Normal file
1016
indra/newview/llvoicevivox.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater bottom="0" can_drag_on_left="false" can_minimize="true" can_resize="false"
|
||||
height="260" left="0" name="floater_device_settings"
|
||||
title="Voice Chat Device Settings" width="405">
|
||||
<panel bottom="0" filename="panel_audio_device.xml" left="2" name="device_settings"
|
||||
right="-5" top="-20" />
|
||||
</floater>
|
||||
@@ -7284,6 +7284,56 @@ We are creating a voice channel for you. This may take up to one minute.
|
||||
<unique/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notify.tga"
|
||||
name="VoiceEffectsExpired"
|
||||
sound="UISndAlert"
|
||||
persist="true"
|
||||
type="notify">
|
||||
<unique/>
|
||||
One or more of your subscribed Voice Morphs has expired.
|
||||
[[URL] Click here] to renew your subscription.
|
||||
<tag>fail</tag>
|
||||
<tag>voice</tag>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notify.tga"
|
||||
name="VoiceEffectsExpiredInUse"
|
||||
sound="UISndAlert"
|
||||
persist="true"
|
||||
type="notify">
|
||||
<unique/>
|
||||
The active Voice Morph has expired, your normal voice settings have been applied.
|
||||
[[URL] Click here] to renew your subscription.
|
||||
<tag>fail</tag>
|
||||
<tag>voice</tag>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notify.tga"
|
||||
name="VoiceEffectsWillExpire"
|
||||
sound="UISndAlert"
|
||||
persist="true"
|
||||
type="notify">
|
||||
<unique/>
|
||||
One or more of your Voice Morphs will expire in less than [INTERVAL] days.
|
||||
[[URL] Click here] to renew your subscription.
|
||||
<tag>fail</tag>
|
||||
<tag>voice</tag>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notify.tga"
|
||||
name="VoiceEffectsNew"
|
||||
sound="UISndAlert"
|
||||
persist="true"
|
||||
type="notify">
|
||||
<unique/>
|
||||
New Voice Morphs are available!
|
||||
<tag>voice</tag>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notifytip.tga"
|
||||
name="Cannot enter parcel: not a group member"
|
||||
@@ -7422,6 +7472,23 @@ Avatar '[NAME]' left after [TIME] seconds as cloud.
|
||||
Avatar '[NAME]' entered appearance mode.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="NoVoiceConnect"
|
||||
type="alertmodal">
|
||||
We're having trouble connecting to your voice server:
|
||||
|
||||
[HOSTID]
|
||||
|
||||
Voice communications will not be available.
|
||||
Please check your network and firewall setup.
|
||||
<tag>voice</tag>
|
||||
<tag>fail</tag>
|
||||
<usetemplate
|
||||
name="okbutton"
|
||||
yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notifytip.tga"
|
||||
name="AvatarRezLeftAppearanceNotification"
|
||||
@@ -8998,14 +9065,6 @@ Only the first 10 selected objects have been disabled. Refresh and make addition
|
||||
You need to update your viewer to buy this parcel.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="LandBuyAccessBlocked"
|
||||
type="notify">
|
||||
<tag>fail</tag>
|
||||
You can't buy this land due to your maturity Rating. You may need to validate your age and/or install the latest Viewer. Please go to the Knowledge Base for details on accessing areas with this maturity Rating.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="CantBuyParcelNotForSale"
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<panel border="false" bottom="0" enabled="true" height="240" left="8"
|
||||
mouse_opaque="true" name="device_settings" width="404">
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
drop_shadow_visible="true" enabled="true" follows="left|top"
|
||||
font="SansSerifSmall" h_pad="0" halign="left" height="16" left="6"
|
||||
mouse_opaque="true" name="Audio Devices" v_pad="0" width="200">
|
||||
Audio Devices
|
||||
</text>
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-22" drop_shadow_visible="true" enabled="true"
|
||||
follows="left|top" font="SansSerifSmall" h_pad="0" halign="left"
|
||||
height="16" left="20" mouse_opaque="true" name="Input device (microphone):"
|
||||
v_pad="0" width="200">
|
||||
Input device (microphone):
|
||||
</text>
|
||||
<combo_box allow_text_entry="false" bottom_delta="-20" enabled="true" follows="left|top"
|
||||
height="18" left_delta="0" max_chars="128" mouse_opaque="true"
|
||||
name="voice_input_device" width="225" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-25" drop_shadow_visible="true" enabled="true"
|
||||
follows="left|top" font="SansSerifSmall" h_pad="0" halign="left"
|
||||
height="16" left_delta="0" mouse_opaque="true"
|
||||
name="Output device (speakers):" v_pad="0" width="200">
|
||||
Output device (speakers):
|
||||
</text>
|
||||
<combo_box allow_text_entry="false" bottom_delta="-20" enabled="true" follows="left|top"
|
||||
height="18" left_delta="0" max_chars="128" mouse_opaque="true"
|
||||
name="voice_output_device" width="225" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-30" drop_shadow_visible="true" enabled="true"
|
||||
follows="left|top" font="SansSerifSmall" h_pad="0" halign="left"
|
||||
height="16" left="6" mouse_opaque="true" name="Input level:" v_pad="0"
|
||||
width="200">
|
||||
Input Level
|
||||
</text>
|
||||
<text_editor type="string" length="1" allow_html="false" bg_readonly_color="0 0 0 0" embedded_items="false"
|
||||
enabled="false" font="SansSerifSmall" height="60" hide_border="true"
|
||||
hide_scrollbar="true" left_delta="10" max_length="65535"
|
||||
mouse_opaque="true" name="voice_intro_text1" tab_stop="false" width="380"
|
||||
word_wrap="true">
|
||||
Adjust the slider to control how loud you sound to other Residents. To test the input level, simply speak into your microphone.
|
||||
</text_editor>
|
||||
<volume_slider bottom_delta="-18" enabled="true" follows="left|top" height="17"
|
||||
increment="0.05" initial_val="1.0" left_delta="5" max_val="2" min_val="0"
|
||||
mouse_opaque="true" name="mic_volume_slider"
|
||||
tool_tip="Change the volume using this slider" width="90" />
|
||||
<text bottom_delta="-4" follows="left|top" height="20" left_delta="95"
|
||||
name="wait_text" width="200">
|
||||
Please wait
|
||||
</text>
|
||||
<locate bottom_delta="-5" height="20" left_delta="0" name="bar0" width="20" />
|
||||
<locate bottom_delta="0" height="20" left_delta="22" name="bar1" width="20" />
|
||||
<locate bottom_delta="0" height="20" left_delta="22" name="bar2" width="20" />
|
||||
<locate bottom_delta="0" height="20" left_delta="22" name="bar3" width="20" />
|
||||
<locate bottom_delta="0" height="20" left_delta="22" name="bar4" width="20" />
|
||||
<string name="default_text">
|
||||
Default
|
||||
</string>
|
||||
</panel>
|
||||
@@ -7,22 +7,14 @@
|
||||
<radio_item bottom="-35" height="16" name="1">Hear Voice Chat from avatar position.</radio_item>
|
||||
</radio_group>
|
||||
<text bottom_delta="-20" follows="top" height="16" name="push_to_talk_heading">Push To Talk</text>
|
||||
<text bottom_delta="-77" follows="top" height="65" left_delta="20" name="voice_chat_description">
|
||||
Push-to-Talk mode lets you control when your voice is transmitted. When in toggle mode,
|
||||
press and release the push-to-talk trigger to switch your microphone on and off.
|
||||
When not in toggle mode, the microphone is active only when the trigger is held down.
|
||||
</text>
|
||||
<check_box bottom_delta="-20" follows="top" height="16" initial_value="false" label="Use Push-to-Talk in toggle mode" name="push_to_talk_toggle_check"/>
|
||||
<check_box bottom_delta="-20" follows="top" height="16" initial_value="false" label="Use Push-to-Talk in toggle mode" name="push_to_talk_toggle_check" tool_tip="When enabled, press the push-to-talk trigger to switch your microphone on and off. When disabled, the microphone is off unless the trigger is being held down."/>
|
||||
<text bottom_delta="-20" follows="top" height="16" left_delta="4" name="push_to_talk_label">Push-to-Talk trigger:</text>
|
||||
<line_editor bottom_delta="-20" follows="top" height="19" name="modifier_combo" width="280"/>
|
||||
<button bottom_delta="-25" follows="top" height="20" label="Set Key" name="set_voice_hotkey_button" width="115"/>
|
||||
<button bottom_delta="0" follows="top" height="20" label="Middle Mouse Button" left_delta="120" name="set_voice_middlemouse_button" width="160"/>
|
||||
<text bottom_delta="-25" follows="top" height="16" left="28" name="lip_sync_heading" width="445">Lip Sync Mouth Animation</text>
|
||||
<check_box bottom_delta="-20" follows="top" height="16" initial_value="false" label="Enable lip sync animation" left_delta="20" name="enable_lip_sync_check"/>
|
||||
<text bottom_delta="-25" follows="top" height="16" left="28" name="privacy_heading">Privacy Options</text>
|
||||
<check_box bottom_delta="-20" follows="top" height="16" initial_value="false" label="Only accept voice calls from people on My Friends list" left_delta="20" name="voice_call_friends_only_check"/>
|
||||
<check_box bottom_delta="-24" follows="top" height="16" initial_value="false" label="Enable lip sync animation" left="28" name="enable_lip_sync_check"/>
|
||||
<check_box bottom_delta="-20" follows="top" height="16" initial_value="false" label="Only accept voice calls from people on My Friends list" name="voice_call_friends_only_check"/>
|
||||
<check_box bottom_delta="-18" follows="top" height="16" initial_value="false" label="Switch off microphone when ending IM calls" name="auto_disengage_mic_check"/>
|
||||
<button bottom_delta="-40" follows="top" height="20" label="Device Settings" left="28" mouse_opaque="true" name="device_settings_btn" width="155"/>
|
||||
<text bottom_delta="-36" follows="top" height="35" left_delta="6" name="device_settings_text">NOTE: Running the Device Settings will temporarily disconnect you from Voice Chat,
|
||||
and changes you make will be immediately applied.</text>
|
||||
<button control_name="ShowDeviceSettings" toggle="true" bottom_delta="-40" follows="top" height="20" label="Device Settings" mouse_opaque="true" name="device_settings_btn" width="155" tool_tip="Running the Device Settings will temporarily disconnect you from Voice Chat, and changes you make will be immediately applied."/>
|
||||
<panel name="device_settings_panel" filename="panel_sound_devices.xml" follows="all" visible="false"/>
|
||||
</panel>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<panel border="false" bottom="0" enabled="true" height="240" left="8"
|
||||
mouse_opaque="true" name="device_settings_panel" width="404">
|
||||
<string
|
||||
name="default_text">
|
||||
Default
|
||||
</string>
|
||||
<string
|
||||
name="name_no_device">
|
||||
No Device
|
||||
</string>
|
||||
<string
|
||||
name="name_default_system_device">
|
||||
Default System Device
|
||||
</string>
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-22" drop_shadow_visible="true" enabled="true"
|
||||
follows="left|top" font="SansSerifSmall" h_pad="0" halign="left"
|
||||
height="16" left="20" mouse_opaque="true" name="Input"
|
||||
v_pad="0" width="200">
|
||||
Input (microphone):
|
||||
</text>
|
||||
<combo_box control_name="VoiceInputAudioDevice" allow_text_entry="false" bottom_delta="-20" enabled="true" follows="left|top"
|
||||
height="18" left_delta="0" max_chars="128" mouse_opaque="true"
|
||||
name="voice_input_device" width="225" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="-54" drop_shadow_visible="true" enabled="true"
|
||||
follows="left|top" font="SansSerifSmall" h_pad="0" halign="left"
|
||||
height="16" left_delta="0" mouse_opaque="true"
|
||||
name="Output" v_pad="0" width="200">
|
||||
Output (speakers):
|
||||
</text>
|
||||
<combo_box control_name="VoiceOutputAudioDevice" allow_text_entry="false" bottom_delta="-20" enabled="true" follows="left|top"
|
||||
height="18" left_delta="0" max_chars="128" mouse_opaque="true"
|
||||
name="voice_output_device" width="225" />
|
||||
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
|
||||
bottom_delta="52" drop_shadow_visible="true" enabled="true"
|
||||
follows="left|top" font="SansSerifSmall" h_pad="0" halign="left"
|
||||
height="16" mouse_opaque="true" name="My volume label" v_pad="0"
|
||||
width="200">
|
||||
Input Level:
|
||||
</text>
|
||||
<volume_slider control_name="AudioLevelMic" bottom_delta="-12" left_delta="-6" follows="left|top" height="17"
|
||||
increment="0.05" initial_val="1.0" max_val="2" min_val="0"
|
||||
mouse_opaque="true" name="mic_volume_slider"
|
||||
tool_tip="Change the volume using this slider" width="120" />
|
||||
<text bottom_delta="-4" follows="left|top" height="20" left_delta="120"
|
||||
name="wait_text" width="200">
|
||||
Please wait
|
||||
</text>
|
||||
<locate bottom_delta="40" height="20" left_delta="0" name="bar0" width="20" />
|
||||
<locate bottom_delta="0" height="20" left_delta="22" name="bar1" width="20" />
|
||||
<locate bottom_delta="0" height="20" left_delta="22" name="bar2" width="20" />
|
||||
<locate bottom_delta="0" height="20" left_delta="22" name="bar3" width="20" />
|
||||
<locate bottom_delta="0" height="20" left_delta="22" name="bar4" width="20" />
|
||||
</panel>
|
||||
@@ -4110,6 +4110,8 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
|
||||
|
||||
<string name="Home position set.">Home position set.</string>
|
||||
|
||||
<string name="voice_morphing_url">http://secondlife.com/landing/voicemorphing</string>
|
||||
|
||||
<!-- Financial operations strings -->
|
||||
<string name="paid_you_ldollars">[NAME] paid you [CURRENCY][AMOUNT] [REASON].</string>
|
||||
<string name="paid_you_ldollars_no_reason">[NAME] paid you [CURRENCY][AMOUNT].</string>
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater name="floater_device_settings" title="Configuración Dispositivos de Voz"/>
|
||||
@@ -4077,6 +4077,25 @@ Pulsa Aceptar para entrar al chat o Rehusar para declinar la invitación. Pulsa
|
||||
<notification name="VoiceLoginRetry">
|
||||
Estamos creando un canal de voz para ti. Esto puede tardar hasta un minuto.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsExpired">
|
||||
Una o más de las transformaciones de voz a las que estás suscrito han caducado.
|
||||
[Pulsa aquí [URL]] para renovar la suscripción.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsExpiredInUse">
|
||||
La transformación de voz activa ha caducado y se ha aplicado tu configuración de voz normal.
|
||||
[Pulsa aquí [URL]] para renovar la suscripción.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsWillExpire">
|
||||
Una o más de tus transformaciones de voz caducarán en menos de [INTERVAL] días.
|
||||
[Pulsa aquí [URL]] para renovar la suscripción.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsNew">
|
||||
Están disponibles nuevas transformaciones de voz.
|
||||
</notification>
|
||||
|
||||
<notification name="Cannot enter parcel: not a group member">
|
||||
No puedes entrar en esta parcela, no eres miembro del grupo adecuado.
|
||||
@@ -4157,6 +4176,16 @@ Avatar '[NAME]' se fué después de [TIME] segundos siendo nube.
|
||||
Avatar '[NAME]' ha entrado en edición de Apariencia.
|
||||
</notification>
|
||||
|
||||
<notification name="NoVoiceConnect">
|
||||
Tenemos problemas de conexión con tu servidor de voz:
|
||||
|
||||
[HOSTID]
|
||||
|
||||
No podrás establecer comunicaciones de voz.
|
||||
Comprueba la configuración de la red y del servidor de seguridad.
|
||||
<usetemplate name="okbutton" yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
<notification name="AvatarRezLeftAppearanceNotification">
|
||||
( [EXISTENCE] segundos vivo )
|
||||
Avatar '[NAME]' ha abandonado la edición de su Apariencia.
|
||||
@@ -5134,11 +5163,6 @@ la región está llena.
|
||||
Necesitas actualizar tu visor para comprar esta parcela.
|
||||
</notification>
|
||||
|
||||
<notification name="LandBuyAccessBlocked">
|
||||
<tag>fail</tag>
|
||||
No puedes comprar este terreno por tu nivel de calificación. Necesitas validar tu edad y/o instalar un visor actualizado. Por favor dirígete a la base de conocimientos para más detalles sobre como acceder a áreas con calificación de edad.
|
||||
</notification>
|
||||
|
||||
<notification name="CantBuyParcelNotForSale">
|
||||
<tag>fail</tag>
|
||||
Incapaz de comprar, esta parcela no está en venta.
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<panel name="device_settings">
|
||||
<text name="Audio Devices">
|
||||
Dispositivos de Audio
|
||||
</text>
|
||||
<text name="Input device (microphone):">
|
||||
Dispostitivo de Entrada (micrófono):
|
||||
</text>
|
||||
<text name="Output device (speakers):">
|
||||
Dispositivo de Salida (parlantes):
|
||||
</text>
|
||||
<text name="Input level:">
|
||||
Nivel de Entrada
|
||||
</text>
|
||||
<text_editor name="voice_intro_text1">
|
||||
Ajusta el control deslizante para variar el volumen en que te escucharán los otros residentes. Para probar el nivel de entrada, simplemente habla en tu micrófono.
|
||||
</text_editor>
|
||||
<volume_slider name="mic_volume_slider" tool_tip="Cambia el volumen usando este control deslizante" />
|
||||
<text name="wait_text">
|
||||
Espera por favor
|
||||
</text>
|
||||
<string name="default_text">
|
||||
Por defecto
|
||||
</string>
|
||||
</panel>
|
||||
@@ -15,30 +15,14 @@
|
||||
<text name="push_to_talk_heading">
|
||||
Apretar para Hablar
|
||||
</text>
|
||||
<text name="voice_chat_description">
|
||||
El modo Apretar para Hablar controla cuándo tu voz se transmite. En el modo
|
||||
'un toque', pulsa y suelta el botón Apretar para Hablar para activar y desactivar
|
||||
tu micrófono. Si no se está en el modo 'un toque', el micrófono está activo
|
||||
sólo cuando se mantiene pulsado el botón.
|
||||
</text>
|
||||
<check_box label="Usar Apretar para Hablar en el modo 'Un Toque'" name="push_to_talk_toggle_check"/>
|
||||
<check_box label="Usar Apretar para Hablar en el modo 'Un Toque'" name="push_to_talk_toggle_check" tool_tip="El modo Apretar para Hablar controla cuándo tu voz se transmite. En el modo 'un toque', pulsa y suelta el botón Apretar para Hablar para activar y desactivar tu micrófono. Si no se está en el modo 'un toque', el micrófono está activo sólo cuando se mantiene pulsado el botón."/>
|
||||
<text name="push_to_talk_label">
|
||||
Botón Apretar para Hablar:
|
||||
</text>
|
||||
<button label="Definir Tecla" name="set_voice_hotkey_button" width="115"/>
|
||||
<button label="Botón medio del Ratón" left_delta="120" name="set_voice_middlemouse_button" width="160"/>
|
||||
<text name="lip_sync_heading" width="445">
|
||||
Activar animación de Labios
|
||||
</text>
|
||||
<check_box label="Activar Animación de Labios" left_delta="20" name="enable_lip_sync_check"/>
|
||||
<text name="privacy_heading">
|
||||
Opciones de Privacidad
|
||||
</text>
|
||||
<check_box label="Aceptar llamadas sólo de mis contactos" left_delta="20" name="voice_call_friends_only_check"/>
|
||||
<check_box label="Aceptar llamadas sólo de mis contactos" name="voice_call_friends_only_check"/>
|
||||
<check_box label="Apagar el micrófono al terminar la llamada por MI" name="auto_disengage_mic_check"/>
|
||||
<button label="Configuración de Dispositivos" left="28" name="device_settings_btn" width="200"/>
|
||||
<text name="device_settings_text">
|
||||
NOTA: Ejecutar esta configuración te desconectará temporalmente del chat de voz,
|
||||
y los cambios se aplicarán inmediatamente..
|
||||
</text>
|
||||
<button label="Configuración de Dispositivos" name="device_settings_btn" width="200" tool_tip="Ejecutar esta configuración te desconectará temporalmente del chat de voz, y los cambios se aplicarán inmediatamente.."/>
|
||||
</panel>
|
||||
|
||||
25
indra/newview/skins/default/xui/es/panel_sound_devices.xml
Normal file
25
indra/newview/skins/default/xui/es/panel_sound_devices.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<panel label="Configuración del dispositivo" name="device_settings_panel">
|
||||
<string name="default_text">
|
||||
Por defecto
|
||||
</string>
|
||||
<string name="name_no_device">
|
||||
Ningún dispositivo
|
||||
</string>
|
||||
<string name="name_default_system_device">
|
||||
Dispositivo del sistema por defecto
|
||||
</string>
|
||||
<text name="Input">
|
||||
Entrada
|
||||
</text>
|
||||
<text name="Output">
|
||||
Salida
|
||||
</text>
|
||||
<text name="My volume label">
|
||||
Mi volumen:
|
||||
</text>
|
||||
<slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Cambia el volumen usando este deslizable"/>
|
||||
<text name="wait_text">
|
||||
Por favor, espera
|
||||
</text>
|
||||
</panel>
|
||||
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater name="floater_device_settings" title="Paramètres du matériel utilisé pour le chat vocal"/>
|
||||
@@ -3674,6 +3674,25 @@ Echec de la connexion avec [VOICE_CHANNEL_NAME], veuillez réessayer ultérieure
|
||||
Nous sommes en train de créer un canal vocal pour vous. Veuillez patienter quelques instants.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsExpired">
|
||||
Au moins l'un des effets de voix auxquels vous êtes abonné a expiré.
|
||||
[[URL] Cliquez ici] pour renouveler votre abonnement.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsExpiredInUse">
|
||||
L'effet de voix actif a expiré. Vos paramètres de voix normaux ont été rétablis.
|
||||
[[URL] Cliquez ici] pour renouveler votre abonnement.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsWillExpire">
|
||||
Au moins l'un de vos effets de voix expirera dans moins de [INTERVAL] jours.
|
||||
[[URL] Cliquez ici] pour renouveler votre abonnement.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsNew">
|
||||
De nouveaux effets de voix sont disponibles !
|
||||
</notification>
|
||||
|
||||
<notification name="Cannot enter parcel: not a group member">
|
||||
Vous ne pouvez pas pénétrer sur ce terrain car vous n'êtes pas membre du groupe adéquat.
|
||||
</notification>
|
||||
@@ -3819,6 +3838,15 @@ votre display name doit contenir des lettres autres que de la simple ponctuation
|
||||
[OLD_NAME] ([SLID]) est maintenant connu(e) comme [NEW_NAME].
|
||||
</notification>
|
||||
|
||||
<notification name="NoVoiceConnect">
|
||||
Problèmes de connexion à votre serveur vocal :
|
||||
|
||||
[HOSTID]
|
||||
|
||||
Aucune communication vocale n'est disponible.
|
||||
Veuillez vérifier la configuration de votre réseau et de votre pare-feu.
|
||||
<usetemplate name="okbutton" yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<panel name="device_settings">
|
||||
<text name="Audio Devices">
|
||||
Matériel audio
|
||||
</text>
|
||||
<text name="Input device (microphone):">
|
||||
Périphérique d'entrée (micro):
|
||||
</text>
|
||||
<text name="Output device (speakers):">
|
||||
Périphérique de sortie (haut-parleurs):
|
||||
</text>
|
||||
<text name="Input level:">
|
||||
Volume d'entrée
|
||||
</text>
|
||||
<text_editor name="voice_intro_text1">
|
||||
Pour que les autres résidents vous entendent plus ou moins fort, utilisez le curseur. Pour tester le volume, parlez dans le micro.
|
||||
</text_editor>
|
||||
<volume_slider name="mic_volume_slider" tool_tip="Réglez le volume avec ce curseur."/>
|
||||
<text name="wait_text">
|
||||
Veuillez patienter...
|
||||
</text>
|
||||
<string name="default_text">
|
||||
Défaut
|
||||
</string>
|
||||
</panel>
|
||||
@@ -7,23 +7,12 @@
|
||||
<radio_item name="1">Ecouter depuis la position de l'avatar</radio_item>
|
||||
</radio_group>
|
||||
<text name="push_to_talk_heading">Appuyer pour parler</text>
|
||||
<text name="voice_chat_description">
|
||||
Ce mode vous permet de contrôler l'ouverture du micro en mode bascule.
|
||||
Cliquez sur la touche de contrôle ou le bouton "Parler" pour ouvrir et fermer le micro.
|
||||
Si vous n'êtes pas en mode bascule, le micro n'est ouvert que si vous cliquez et
|
||||
maintenez enfoncés la touche de contrôle ou appuyez sur le bouton "Parler".
|
||||
</text>
|
||||
<check_box label="Utiliser "Appuyer pour Parler" en mode bascule" name="push_to_talk_toggle_check"/>
|
||||
<check_box label="Utiliser "Appuyer pour Parler" en mode bascule" name="push_to_talk_toggle_check" tool_tip="Ce mode vous permet de contrôler l'ouverture du micro en mode bascule. Cliquez sur la touche de contrôle ou le bouton "Parler" pour ouvrir et fermer le micro. Si vous n'êtes pas en mode bascule, le micro n'est ouvert que si vous cliquez et maintenez enfoncés la touche de contrôle ou appuyez sur le bouton "Parler"."/>
|
||||
<text name="push_to_talk_label">Touche de contrôle:</text>
|
||||
<button bottom_delta="-25" label="Choisir la touche" name="set_voice_hotkey_button"/>
|
||||
<button label="Choisir la touche" name="set_voice_hotkey_button"/>
|
||||
<button label="Molette de la souris" name="set_voice_middlemouse_button"/>
|
||||
<text name="lip_sync_heading">Animation en mode "voice"</text>
|
||||
<check_box label="Activer l'animation des lèvres" name="enable_lip_sync_check"/>
|
||||
<text name="privacy_heading">Options de confidentialité</text>
|
||||
<check_box label="N'accepter que les appels des amis" name="voice_call_friends_only_check"/>
|
||||
<check_box label="Fermer le micro à la fin d'un appel privé" name="auto_disengage_mic_check"/>
|
||||
<button label="Paramètres du matériel" name="device_settings_btn"/>
|
||||
<text name="device_settings_text">Remarque : Si vous cliquez sur Paramètres du matériel,
|
||||
vous serez temporairement déconnecté(e) du Chat vocal.
|
||||
Tous les changements que vous faites seront immédiatement appliqués.</text>
|
||||
<button label="Paramètres du matériel" name="device_settings_btn" tool_tip="Si vous cliquez sur Paramètres du matériel, vous serez temporairement déconnecté(e) du Chat vocal. Tous les changements que vous faites seront immédiatement appliqués."/>
|
||||
</panel>
|
||||
|
||||
25
indra/newview/skins/default/xui/fr/panel_sound_devices.xml
Normal file
25
indra/newview/skins/default/xui/fr/panel_sound_devices.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<panel label="Paramètres du périphérique" name="device_settings_panel">
|
||||
<string name="default_text">
|
||||
Valeur par défaut
|
||||
</string>
|
||||
<string name="name_no_device">
|
||||
Aucun périphérique
|
||||
</string>
|
||||
<string name="name_default_system_device">
|
||||
Périphérique système par défaut
|
||||
</string>
|
||||
<text name="Input">
|
||||
Entrée
|
||||
</text>
|
||||
<text name="Output">
|
||||
Sortie
|
||||
</text>
|
||||
<text name="My volume label">
|
||||
Mon volume :
|
||||
</text>
|
||||
<slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Régler le volume avec le curseur."/>
|
||||
<text name="wait_text">
|
||||
Veuillez patienter
|
||||
</text>
|
||||
</panel>
|
||||
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="floater_device_settings" title="Ajustes do Dispositivo de Conversa por Voz"/>
|
||||
@@ -3284,6 +3284,15 @@ Autorizar este pedido?
|
||||
</form>
|
||||
</notification>
|
||||
|
||||
<notification name="NoVoiceConnect">
|
||||
Estamos tendo problemas de conexão com o seu servidor de voz:
|
||||
|
||||
[HOSTID]
|
||||
|
||||
Talvez não seja possível se comunicar via voz.
|
||||
Verifique a configuração da sua rede e firewall.
|
||||
<usetemplate name="okbutton" yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
<notification name="FirstBalanceIncrease">
|
||||
Você recebeu uma quantia de [CURRENCY][AMOUNT].
|
||||
@@ -3463,6 +3472,25 @@ Clique Aceitar para juntar-se à chamada ou Recusar para recusar o convite. Cliq
|
||||
Estamos criando uma canal de voz para você. Isto pode levar até um minuto.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsExpired">
|
||||
Um ou mais serviços de distorção de voz que você assinou veceu.
|
||||
[[URL] Clique aqui] para renovar o serviço.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsExpiredInUse">
|
||||
A Distorção de voz ativa expirou. Suas configurações de voz padrão foram ativadas.
|
||||
[[URL] Clique aqui] para renovar o serviço.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsWillExpire">
|
||||
Uma ou mais das suas distorções de voz tem vencimento em menos de [INTERVAL] dias.
|
||||
[[URL] Clique aqui] para renovar o serviço.
|
||||
</notification>
|
||||
|
||||
<notification name="VoiceEffectsNew">
|
||||
Novas Distorções de voz!
|
||||
</notification>
|
||||
|
||||
<notification name="Cannot enter parcel: not a group member">
|
||||
Você não pode entrar nessa terra, você não é membro do grupo autorizado.
|
||||
</notification>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<panel name="device_settings">
|
||||
<text name="Audio Devices">
|
||||
Dispositivos de Áudio
|
||||
</text>
|
||||
<text name="Input device (microphone):">
|
||||
Dispositivo de entrada (microfone):
|
||||
</text>
|
||||
<text name="Output device (speakers):">
|
||||
Dispositivo de saída (falantes):
|
||||
</text>
|
||||
<text name="Input level:">
|
||||
Nível de Entrada
|
||||
</text>
|
||||
<text_editor name="voice_intro_text1">
|
||||
Ajuste a barra para controlar o volume de som para os outros residentes. Para testar o nível de entrada, basta falar em seu microfone.
|
||||
</text_editor>
|
||||
<volume_slider name="mic_volume_slider" tool_tip="Altere o volume usando este controle gradual"/>
|
||||
<text name="wait_text">
|
||||
Por Favor aguarde
|
||||
</text>
|
||||
<string name="default_text">
|
||||
Padrão
|
||||
</string>
|
||||
</panel>
|
||||
@@ -15,22 +15,10 @@
|
||||
<text name="push_to_talk_heading">
|
||||
Pressione para falar
|
||||
</text>
|
||||
<text_editor name="voice_chat_description" width="465" bottom_delta="-76" height="81" >
|
||||
O modo Pressione-para-falar permite que você controle quando a sua voz é transmitida. Quando quiser alternar o modo, pressione e solte o botão pressione-para-falar para mudar o seu microfone de ligado para desligado. Quando não estiver em modo alternado, o microfone estará ativo apenas quando o botão estiver mantido para baixo.
|
||||
</text_editor>
|
||||
<check_box label="Use Pressione-para-falar em modo alternado" name="push_to_talk_toggle_check"/>
|
||||
<text name="push_to_talk_label">
|
||||
Gatilho do Pressione-para-Falar:
|
||||
</text>
|
||||
<check_box label="Use Pressione-para-falar em modo alternado" name="push_to_talk_toggle_check" tool_tip="O modo Pressione-para-falar permite que você controle quando a sua voz é transmitida. Quando quiser alternar o modo, pressione e solte o botão pressione-para-falar para mudar o seu microfone de ligado para desligado. Quando não estiver em modo alternado, o microfone estará ativo apenas quando o botão estiver mantido para baixo."/>
|
||||
<button label="Definir tecla" name="set_voice_hotkey_button"/>
|
||||
<button label="Botão do meio do mouse" name="set_voice_middlemouse_button"/>
|
||||
<text name="privacy_heading">
|
||||
Opções de privacidade
|
||||
</text>
|
||||
<check_box label="Apenas aceitar chamadas de voz das pessoas da minha Lista de amigos" name="voice_call_friends_only_check"/>
|
||||
<check_box label="Desligar o microfone quando terminar chamadas por MI" name="auto_disengage_mic_check"/>
|
||||
<button label="Configurações do dispositivo" name="device_settings_btn" width="180"/>
|
||||
<text_editor bottom_delta="-45" height="48" name="device_settings_text">
|
||||
NOTA: Executar as configurações do dispositivo vai desligá-lo temporariamente do Bate- papo de voz e as mudanças que você fizer serão imediatamente aplicadas.
|
||||
</text_editor>
|
||||
<button label="Configurações do dispositivo" name="device_settings_btn" width="180" tool_tip="Executar as configurações do dispositivo vai desligá-lo temporariamente do Bate- papo de voz e as mudanças que você fizer serão imediatamente aplicadas."/>
|
||||
</panel>
|
||||
|
||||
25
indra/newview/skins/default/xui/pt/panel_sound_devices.xml
Normal file
25
indra/newview/skins/default/xui/pt/panel_sound_devices.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<panel label="Configuração de dispositivos" name="device_settings_panel">
|
||||
<string name="default_text">
|
||||
Padrão
|
||||
</string>
|
||||
<string name="name_no_device">
|
||||
Nenhum
|
||||
</string>
|
||||
<string name="name_default_system_device">
|
||||
Dispositivo padrão do sistema
|
||||
</string>
|
||||
<text name="Input">
|
||||
Entrada
|
||||
</text>
|
||||
<text name="Output">
|
||||
Saída
|
||||
</text>
|
||||
<text name="My volume label">
|
||||
Meu volume:
|
||||
</text>
|
||||
<slider_bar initial_value="1.0" name="mic_volume_slider" tool_tip="Mude o volume usando o controle deslizante"/>
|
||||
<text name="wait_text">
|
||||
Aguarde
|
||||
</text>
|
||||
</panel>
|
||||
Reference in New Issue
Block a user