EXT-7138 WIP Merged Voice fonts work into the newly modularized LLVoiceClient.
Created LLVoiceEffectInterface as an optional interface to be implemented by voice modules that support voice effects.master
commit
9cec4bdd69
|
|
@ -352,6 +352,7 @@ set(viewer_SOURCE_FILES
|
|||
llpanelprofileview.cpp
|
||||
llpanelteleporthistory.cpp
|
||||
llpaneltiptoast.cpp
|
||||
llpanelvoiceeffect.cpp
|
||||
llpanelvolume.cpp
|
||||
llpanelvolumepulldown.cpp
|
||||
llparcelselection.cpp
|
||||
|
|
@ -863,6 +864,7 @@ set(viewer_HEADER_FILES
|
|||
llpanelprofileview.h
|
||||
llpanelteleporthistory.h
|
||||
llpaneltiptoast.h
|
||||
llpanelvoiceeffect.h
|
||||
llpanelvolume.h
|
||||
llpanelvolumepulldown.h
|
||||
llparcelselection.h
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
</array>
|
||||
<key>tags</key>
|
||||
<array>
|
||||
<string>Voice</string>
|
||||
</array>
|
||||
</map>
|
||||
</array>
|
||||
|
|
|
|||
|
|
@ -10595,6 +10595,28 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>VoiceFontsAvailable</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Temporary debug setting to test UI with no voice effects available.</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>VoiceEffectEnabled</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not to use Voice Effects 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>
|
||||
|
|
|
|||
|
|
@ -99,6 +99,17 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>VoiceEffectDefault</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Selected voice effect</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>00000000-0000-0000-0000-000000000000</string>
|
||||
</map>
|
||||
|
||||
<!-- Settings below are for back compatibility only.
|
||||
They are not used in current viewer anymore. But they can't be removed to avoid
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static void* create_non_avatar_caller(void*)
|
|||
return new LLNonAvatarCaller;
|
||||
}
|
||||
|
||||
LLVoiceChannel* LLCallFloater::sCurrentVoiceCanel = NULL;
|
||||
LLVoiceChannel* LLCallFloater::sCurrentVoiceChannel = NULL;
|
||||
|
||||
LLCallFloater::LLCallFloater(const LLSD& key)
|
||||
: LLTransientDockableFloater(NULL, false, key)
|
||||
|
|
@ -113,7 +113,7 @@ LLCallFloater::LLCallFloater(const LLSD& key)
|
|||
mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), voice_left_remove_delay);
|
||||
|
||||
mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL);
|
||||
LLVoiceClient::getInstance()->addObserver(this);
|
||||
LLVoiceClient::instance().addObserver(this);
|
||||
LLTransientFloaterMgr::getInstance()->addControlView(this);
|
||||
|
||||
// force docked state since this floater doesn't save it between recreations
|
||||
|
|
@ -158,7 +158,6 @@ BOOL LLCallFloater::postBuild()
|
|||
|
||||
initAgentData();
|
||||
|
||||
|
||||
connectToChannel(LLVoiceChannel::getCurrentVoiceChannel());
|
||||
|
||||
setIsChrome(true);
|
||||
|
|
@ -204,7 +203,7 @@ void LLCallFloater::draw()
|
|||
}
|
||||
|
||||
// virtual
|
||||
void LLCallFloater::onChange()
|
||||
void LLCallFloater::onParticipantsChanged()
|
||||
{
|
||||
if (NULL == mParticipants) return;
|
||||
updateParticipantsVoiceState();
|
||||
|
|
@ -287,22 +286,22 @@ void LLCallFloater::updateSession()
|
|||
|
||||
if (NULL == mSpeakerManager)
|
||||
{
|
||||
// by default let show nearby chat participants
|
||||
// By default show nearby chat participants
|
||||
mSpeakerManager = LLLocalSpeakerMgr::getInstance();
|
||||
LL_DEBUGS("Voice") << "Set DEFAULT speaker manager" << LL_ENDL;
|
||||
mVoiceType = VC_LOCAL_CHAT;
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
|
||||
//hide "Leave Call" button for nearby chat
|
||||
|
||||
// Hide "Leave Call" button for nearby chat
|
||||
bool is_local_chat = mVoiceType == VC_LOCAL_CHAT;
|
||||
childSetVisible("leave_call_btn_panel", !is_local_chat);
|
||||
|
||||
refreshParticipantList();
|
||||
updateAgentModeratorState();
|
||||
|
||||
//show floater for voice calls & only in CONNECTED to voice channel state
|
||||
// Show floater for voice calls & only in CONNECTED to voice channel state
|
||||
if (!is_local_chat &&
|
||||
voice_channel &&
|
||||
LLVoiceChannel::STATE_CONNECTED == voice_channel->getState())
|
||||
|
|
@ -368,7 +367,7 @@ void LLCallFloater::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)
|
|||
// *NOTE: if signal was sent for voice channel with LLVoiceChannel::STATE_NO_CHANNEL_INFO
|
||||
// it sill be sent for the same channel again (when state is changed).
|
||||
// So, lets ignore this call.
|
||||
if (channel == sCurrentVoiceCanel) return;
|
||||
if (channel == sCurrentVoiceChannel) return;
|
||||
|
||||
LLCallFloater* call_floater = LLFloaterReg::getTypedInstance<LLCallFloater>("voice_controls");
|
||||
|
||||
|
|
@ -715,9 +714,9 @@ void LLCallFloater::connectToChannel(LLVoiceChannel* channel)
|
|||
{
|
||||
mVoiceChannelStateChangeConnection.disconnect();
|
||||
|
||||
sCurrentVoiceCanel = channel;
|
||||
sCurrentVoiceChannel = channel;
|
||||
|
||||
mVoiceChannelStateChangeConnection = sCurrentVoiceCanel->setStateChangedCallback(boost::bind(&LLCallFloater::onVoiceChannelStateChanged, this, _1, _2));
|
||||
mVoiceChannelStateChangeConnection = sCurrentVoiceChannel->setStateChangedCallback(boost::bind(&LLCallFloater::onVoiceChannelStateChanged, this, _1, _2));
|
||||
|
||||
updateState(channel->getState());
|
||||
}
|
||||
|
|
@ -737,7 +736,7 @@ void LLCallFloater::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old
|
|||
|
||||
void LLCallFloater::updateState(const LLVoiceChannel::EState& new_state)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Updating state: " << new_state << ", session name: " << sCurrentVoiceCanel->getSessionName() << LL_ENDL;
|
||||
LL_DEBUGS("Voice") << "Updating state: " << new_state << ", session name: " << sCurrentVoiceChannel->getSessionName() << LL_ENDL;
|
||||
if (LLVoiceChannel::STATE_CONNECTED == new_state)
|
||||
{
|
||||
updateSession();
|
||||
|
|
|
|||
|
|
@ -47,15 +47,15 @@ class LLSpeakerMgr;
|
|||
class LLSpeakersDelayActionsStorage;
|
||||
|
||||
/**
|
||||
* The Voice Control Panel is an ambient window summoned by clicking the flyout chevron on the Speak button.
|
||||
* It can be torn-off and freely positioned onscreen.
|
||||
* The Voice Control Panel is an ambient window summoned by clicking the flyout chevron
|
||||
* on the Speak button. It can be torn-off and freely positioned onscreen.
|
||||
*
|
||||
* When the Resident is engaged in Nearby Voice Chat, the Voice Control Panel provides control over
|
||||
* the Resident's own microphone input volume, the audible volume of each of the other participants,
|
||||
* the Resident's own Voice Morphing settings (if she has subscribed to enable the feature), and Voice Recording.
|
||||
* When the Resident is engaged in Voice Chat, the Voice Control Panel provides control
|
||||
* over the audible volume of each of the other participants, the Resident's own Voice
|
||||
* Morphing settings (if she has subscribed to enable the feature), and Voice Recording.
|
||||
*
|
||||
* When the Resident is engaged in any chat except Nearby Chat, the Voice Control Panel also provides an
|
||||
* 'Leave Call' button to allow the Resident to leave that voice channel.
|
||||
* When the Resident is engaged in any chat except Nearby Chat, the Voice Control Panel
|
||||
* also provides a 'Leave Call' button to allow the Resident to leave that voice channel.
|
||||
*/
|
||||
class LLCallFloater : public LLTransientDockableFloater, LLVoiceClientParticipantObserver
|
||||
{
|
||||
|
|
@ -75,7 +75,7 @@ public:
|
|||
*
|
||||
* Refreshes list to display participants not in voice as disabled.
|
||||
*/
|
||||
/*virtual*/ void onChange();
|
||||
/*virtual*/ void onParticipantsChanged();
|
||||
|
||||
static void sOnCurrentChannelChanged(const LLUUID& session_id);
|
||||
|
||||
|
|
@ -259,7 +259,7 @@ private:
|
|||
*
|
||||
* @see sOnCurrentChannelChanged()
|
||||
*/
|
||||
static LLVoiceChannel* sCurrentVoiceCanel;
|
||||
static LLVoiceChannel* sCurrentVoiceChannel;
|
||||
|
||||
/* virtual */
|
||||
LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::IM; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
/**
|
||||
* @file llpanelvoiceeffect.cpp
|
||||
* @author Aimee Walton
|
||||
* @brief Panel to select Voice Effects.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2010, 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 "llpanelvoiceeffect.h"
|
||||
|
||||
#include "llcombobox.h"
|
||||
#include "llpanel.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "llvoiceclient.h"
|
||||
|
||||
static LLRegisterPanelClassWrapper<LLPanelVoiceEffect> t_panel_voice_effect("panel_voice_effect");
|
||||
|
||||
LLPanelVoiceEffect::LLPanelVoiceEffect()
|
||||
: mVoiceEffectCombo(NULL)
|
||||
{
|
||||
mCommitCallbackRegistrar.add("Voice.CommitVoiceEffect", boost::bind(&LLPanelVoiceEffect::onCommitVoiceEffect, this));
|
||||
}
|
||||
|
||||
LLPanelVoiceEffect::~LLPanelVoiceEffect()
|
||||
{
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->removeObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLPanelVoiceEffect::postBuild()
|
||||
{
|
||||
mVoiceEffectCombo = getChild<LLComboBox>("voice_effect");
|
||||
update();
|
||||
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->addObserver(this);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// PRIVATE SECTION
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void LLPanelVoiceEffect::onCommitVoiceEffect()
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (!effect_interface)
|
||||
{
|
||||
mVoiceEffectCombo->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
LLSD value = mVoiceEffectCombo->getValue();
|
||||
if (value.asInteger() == GET_VOICE_EFFECTS)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "GET VOICE FONTS!" << LL_ENDL;
|
||||
}
|
||||
else if (value.asInteger() == PREVIEW_VOICE_EFFECTS)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "PREVIEW VOICE FONTS!" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
effect_interface->setVoiceEffect(value.asUUID());
|
||||
}
|
||||
|
||||
mVoiceEffectCombo->setValue(effect_interface->getVoiceEffect());
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLPanelVoiceEffect::onVoiceEffectChanged()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void LLPanelVoiceEffect::update()
|
||||
{
|
||||
if (mVoiceEffectCombo)
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (!effect_interface || !LLVoiceClient::instance().isVoiceWorking())
|
||||
{
|
||||
mVoiceEffectCombo->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
mVoiceEffectCombo->removeall();
|
||||
mVoiceEffectCombo->add(getString("no_voice_effect"), NO_VOICE_EFFECT);
|
||||
mVoiceEffectCombo->addSeparator();
|
||||
|
||||
const voice_effect_list_t& effect_list = effect_interface->getVoiceEffectList();
|
||||
if (!effect_list.empty())
|
||||
{
|
||||
for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
|
||||
{
|
||||
mVoiceEffectCombo->add(it->first, it->second, ADD_BOTTOM);
|
||||
}
|
||||
|
||||
mVoiceEffectCombo->addSeparator();
|
||||
}
|
||||
|
||||
mVoiceEffectCombo->add(getString("get_voice_effects"), GET_VOICE_EFFECTS);
|
||||
mVoiceEffectCombo->add(getString("preview_voice_effects"), PREVIEW_VOICE_EFFECTS);
|
||||
|
||||
mVoiceEffectCombo->setValue(effect_interface->getVoiceEffect());
|
||||
mVoiceEffectCombo->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @file llpanelvoiceeffect.h
|
||||
* @author Aimee Walton
|
||||
* @brief Panel to select Voice Effects.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2010, 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_PANELVOICEEFFECT_H
|
||||
#define LL_PANELVOICEEFFECT_H
|
||||
|
||||
#include "llpanel.h"
|
||||
#include "llvoiceclient.h"
|
||||
|
||||
class LLComboBox;
|
||||
|
||||
class LLPanelVoiceEffect
|
||||
: public LLPanel
|
||||
, public LLVoiceEffectObserver
|
||||
{
|
||||
public:
|
||||
LOG_CLASS(LLPanelVoiceEffect);
|
||||
|
||||
LLPanelVoiceEffect();
|
||||
virtual ~LLPanelVoiceEffect();
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
private:
|
||||
void onCommitVoiceEffect();
|
||||
void update();
|
||||
|
||||
/// Called by voice effect provider when voice effect list is changed.
|
||||
virtual void onVoiceEffectChanged();
|
||||
|
||||
// Fixed entries in the voice effect list
|
||||
typedef enum e_voice_effect_combo_items
|
||||
{
|
||||
NO_VOICE_EFFECT = 0,
|
||||
GET_VOICE_EFFECTS = 1,
|
||||
PREVIEW_VOICE_EFFECTS = 2
|
||||
} EVoiceEffectComboItems;
|
||||
|
||||
LLComboBox* mVoiceEffectCombo;
|
||||
};
|
||||
|
||||
|
||||
#endif //LL_PANELVOICEEFFECT_H
|
||||
|
|
@ -92,7 +92,7 @@ public:
|
|||
mAvalineCallers.insert(avaline_caller_id);
|
||||
}
|
||||
|
||||
void onChange()
|
||||
void onParticipantsChanged()
|
||||
{
|
||||
uuid_set_t participant_uuids;
|
||||
LLVoiceClient::getInstance()->getParticipantList(participant_uuids);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ private:
|
|||
* So, method does not calculate difference between these list it only switches off already
|
||||
* switched on indicators and switches on indicators of voice channel participants
|
||||
*/
|
||||
void onChange();
|
||||
void onParticipantsChanged();
|
||||
|
||||
/**
|
||||
* Changes state of indicators specified by LLUUIDs
|
||||
|
|
@ -205,7 +205,7 @@ void SpeakingIndicatorManager::sOnCurrentChannelChanged(const LLUUID& /*session_
|
|||
mSwitchedIndicatorsOn.clear();
|
||||
}
|
||||
|
||||
void SpeakingIndicatorManager::onChange()
|
||||
void SpeakingIndicatorManager::onParticipantsChanged()
|
||||
{
|
||||
LL_DEBUGS("SpeakingIndicator") << "Voice participant list was changed, updating indicators" << LL_ENDL;
|
||||
|
||||
|
|
|
|||
|
|
@ -891,9 +891,9 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s
|
|||
else
|
||||
{
|
||||
LL_WARNS("Voice") << "incoming SIP URL is not provided. Channel may not work properly." << LL_ENDL;
|
||||
// In case of incoming AvaLine call generated URI will be differ from original one.
|
||||
// This is because Avatar-2-Avatar URI is based on avatar UUID but Avaline is not.
|
||||
// See LLVoiceClient::sessionAddedEvent() -> setUUIDFromStringHash()
|
||||
// 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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ protected:
|
|||
void doSetState(const EState& state);
|
||||
void setURI(std::string uri);
|
||||
|
||||
// there can be two directions ICOMING and OUTGOING
|
||||
// there can be two directions INCOMING and OUTGOING
|
||||
EDirection mCallDirection;
|
||||
|
||||
std::string mURI;
|
||||
|
|
|
|||
|
|
@ -80,9 +80,11 @@ std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserv
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLVoiceClient::LLVoiceClient()
|
||||
LLVoiceClient::LLVoiceClient() :
|
||||
mVoiceModule(NULL),
|
||||
mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceEffectEnabled")),
|
||||
mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault"))
|
||||
{
|
||||
mVoiceModule = NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
|
|
@ -565,7 +567,7 @@ std::string LLVoiceClient::getDisplayName(const LLUUID& id)
|
|||
}
|
||||
}
|
||||
|
||||
bool LLVoiceClient::isVoiceWorking()
|
||||
bool LLVoiceClient::isVoiceWorking() const
|
||||
{
|
||||
if (mVoiceModule)
|
||||
{
|
||||
|
|
@ -708,6 +710,10 @@ std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
|
|||
}
|
||||
}
|
||||
|
||||
LLVoiceEffectInterface* LLVoiceClient::getVoiceEffectInterface() const
|
||||
{
|
||||
return getVoiceEffectEnabled() ? dynamic_cast<LLVoiceEffectInterface*>(mVoiceModule) : NULL;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// version checking
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class LLVOAvatar;
|
|||
#include "llviewerregion.h"
|
||||
#include "llcallingcard.h" // for LLFriendObserver
|
||||
#include "llsecapi.h"
|
||||
#include "llcontrol.h"
|
||||
|
||||
// devices
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ class LLVoiceClientParticipantObserver
|
|||
{
|
||||
public:
|
||||
virtual ~LLVoiceClientParticipantObserver() { }
|
||||
virtual void onChange() = 0;
|
||||
virtual void onParticipantsChanged() = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -109,7 +110,7 @@ public:
|
|||
|
||||
virtual void updateSettings()=0; // call after loading settings and whenever they change
|
||||
|
||||
virtual bool isVoiceWorking()=0; // connected to a voice server and voice channel
|
||||
virtual bool isVoiceWorking() const = 0; // connected to a voice server and voice channel
|
||||
|
||||
virtual const LLVoiceVersionInfo& getVersion()=0;
|
||||
|
||||
|
|
@ -217,8 +218,6 @@ public:
|
|||
//////////////////////////
|
||||
/// @name nearby speaker accessors
|
||||
//@{
|
||||
|
||||
|
||||
virtual BOOL getVoiceEnabled(const LLUUID& id)=0; // true if we've received data for this avatar
|
||||
virtual std::string getDisplayName(const LLUUID& id)=0;
|
||||
virtual BOOL isOnlineSIP(const LLUUID &id)=0;
|
||||
|
|
@ -261,6 +260,49 @@ public:
|
|||
};
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
/// @class LLVoiceEffectObserver
|
||||
class LLVoiceEffectObserver
|
||||
{
|
||||
public:
|
||||
virtual ~LLVoiceEffectObserver() { }
|
||||
virtual void onVoiceEffectChanged() = 0;
|
||||
};
|
||||
|
||||
typedef std::multimap<const std::string, const LLUUID, LLDictionaryLess> voice_effect_list_t;
|
||||
|
||||
//////////////////////////////////
|
||||
/// @class LLVoiceEffectInterface
|
||||
/// @brief Voice effect module interface
|
||||
///
|
||||
/// Voice effect modules should provide an implementation for this interface.
|
||||
/////////////////////////////////
|
||||
|
||||
class LLVoiceEffectInterface
|
||||
{
|
||||
public:
|
||||
LLVoiceEffectInterface() {}
|
||||
virtual ~LLVoiceEffectInterface() {}
|
||||
|
||||
//////////////////////////
|
||||
/// @name Accessors
|
||||
//@{
|
||||
virtual bool setVoiceEffect(const LLUUID& id) = 0;
|
||||
virtual const LLUUID getVoiceEffect() = 0;
|
||||
|
||||
virtual const voice_effect_list_t &getVoiceEffectList() const = 0;
|
||||
virtual const voice_effect_list_t &getVoiceEffectTemplateList() const = 0;
|
||||
//@}
|
||||
|
||||
//////////////////////////////
|
||||
/// @name Status notification
|
||||
//@{
|
||||
virtual void addObserver(LLVoiceEffectObserver* observer) = 0;
|
||||
virtual void removeObserver(LLVoiceEffectObserver* observer) = 0;
|
||||
//@}
|
||||
};
|
||||
|
||||
|
||||
class LLVoiceClient: public LLSingleton<LLVoiceClient>
|
||||
{
|
||||
LOG_CLASS(LLVoiceClient);
|
||||
|
|
@ -281,7 +323,7 @@ public:
|
|||
|
||||
void updateSettings(); // call after loading settings and whenever they change
|
||||
|
||||
bool isVoiceWorking(); // connected to a voice server and voice channel
|
||||
bool isVoiceWorking() const; // connected to a voice server and voice channel
|
||||
|
||||
// tuning
|
||||
void tuningStart();
|
||||
|
|
@ -403,10 +445,23 @@ public:
|
|||
void removeObserver(LLVoiceClientParticipantObserver* observer);
|
||||
|
||||
std::string sipURIFromID(const LLUUID &id);
|
||||
|
||||
|
||||
//////////////////////////
|
||||
/// @name Voice effects
|
||||
//@{
|
||||
bool getVoiceEffectEnabled() const { return mVoiceEffectEnabled; };
|
||||
LLUUID getVoiceEffectDefault() const { return LLUUID(mVoiceEffectDefault); };
|
||||
|
||||
// Returns NULL if voice effects are not supported, or not enabled.
|
||||
LLVoiceEffectInterface* getVoiceEffectInterface() const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
LLVoiceModuleInterface* mVoiceModule;
|
||||
LLPumpIO *m_servicePump;
|
||||
|
||||
LLCachedControl<bool> mVoiceEffectEnabled;
|
||||
LLCachedControl<std::string> mVoiceEffectDefault;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -67,15 +67,11 @@
|
|||
#include "llviewernetwork.h"
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
#include "stringize.h"
|
||||
|
||||
// for base64 decoding
|
||||
#include "apr_base64.h"
|
||||
|
||||
// for SHA1 hash
|
||||
#include "apr_sha1.h"
|
||||
|
||||
// for MD5 hash
|
||||
#include "llmd5.h"
|
||||
|
||||
#define USE_SESSION_GROUPS 0
|
||||
|
||||
const F32 VOLUME_SCALE_VIVOX = 0.01f;
|
||||
|
|
@ -101,14 +97,6 @@ const int MAX_LOGIN_RETRIES = 12;
|
|||
const int MAX_NORMAL_JOINING_SPATIAL_NUM = 50;
|
||||
|
||||
|
||||
static void setUUIDFromStringHash(LLUUID &uuid, const std::string &str)
|
||||
{
|
||||
LLMD5 md5_uuid;
|
||||
md5_uuid.update((const unsigned char*)str.data(), str.size());
|
||||
md5_uuid.finalize();
|
||||
md5_uuid.raw_digest(uuid.mData);
|
||||
}
|
||||
|
||||
static int scale_mic_volume(float volume)
|
||||
{
|
||||
// incoming volume has the range [0.0 ... 2.0], with 1.0 as the default.
|
||||
|
|
@ -325,6 +313,7 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() :
|
|||
mBuddyListMapPopulated(false),
|
||||
mBlockRulesListReceived(false),
|
||||
mAutoAcceptRulesListReceived(false),
|
||||
|
||||
mCaptureDeviceDirty(false),
|
||||
mRenderDeviceDirty(false),
|
||||
mSpatialCoordsDirty(false),
|
||||
|
|
@ -662,6 +651,8 @@ std::string LLVivoxVoiceClient::state2string(LLVivoxVoiceClient::state inState)
|
|||
CASE(stateNeedsLogin);
|
||||
CASE(stateLoggingIn);
|
||||
CASE(stateLoggedIn);
|
||||
CASE(stateVoiceFontsWait);
|
||||
CASE(stateVoiceFontsReceived);
|
||||
CASE(stateCreatingSessionGroup);
|
||||
CASE(stateNoChannel);
|
||||
CASE(stateJoiningSession);
|
||||
|
|
@ -775,8 +766,10 @@ void LLVivoxVoiceClient::stateMachine()
|
|||
// Clean up and reset everything.
|
||||
closeSocket();
|
||||
deleteAllSessions();
|
||||
deleteAllBuddies();
|
||||
|
||||
deleteAllBuddies();
|
||||
deleteVoiceFonts();
|
||||
deleteVoiceFontTemplates();
|
||||
|
||||
mConnectorHandle.clear();
|
||||
mAccountHandle.clear();
|
||||
mAccountPassword.clear();
|
||||
|
|
@ -1222,6 +1215,19 @@ void LLVivoxVoiceClient::stateMachine()
|
|||
|
||||
notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
|
||||
|
||||
// *FIX: Remove VoiceFontsAvailable temporary setting (only used to test UI behaviour with no fonts)
|
||||
if (LLVoiceClient::instance().getVoiceEffectEnabled() && gSavedSettings.getBOOL("VoiceFontsAvailable"))
|
||||
{
|
||||
// request the set of available voice fonts
|
||||
setState(stateVoiceFontsWait);
|
||||
accountGetSessionFontsSendMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(stateVoiceFontsReceived);
|
||||
}
|
||||
accountGetTemplateFontsSendMessage(); // *TODO: Maybe better to do this only when opening preview rather than on login
|
||||
|
||||
// request the current set of block rules (we'll need them when updating the friends list)
|
||||
accountListBlockRulesSendMessage();
|
||||
|
||||
|
|
@ -1253,12 +1259,21 @@ void LLVivoxVoiceClient::stateMachine()
|
|||
writeString(stream.str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//MARK: stateVoiceFontsWait
|
||||
case stateVoiceFontsWait: // Await voice font list
|
||||
// accountGetSessionFontsResponse() will transition from here to
|
||||
// stateVoiceFontsReceived, to ensure we have the voice font list
|
||||
// before attempting to create a session.
|
||||
break;
|
||||
|
||||
//MARK: stateVoiceFontsReceived
|
||||
case stateVoiceFontsReceived: // Voice font list received
|
||||
#if USE_SESSION_GROUPS
|
||||
// create the main session group
|
||||
sessionGroupCreateSendMessage();
|
||||
|
||||
setState(stateCreatingSessionGroup);
|
||||
sessionGroupCreateSendMessage();
|
||||
#else
|
||||
// Not using session groups -- skip the stateCreatingSessionGroup state.
|
||||
setState(stateNoChannel);
|
||||
|
|
@ -1316,6 +1331,7 @@ void LLVivoxVoiceClient::stateMachine()
|
|||
sessionState *oldSession = mAudioSession;
|
||||
|
||||
mAudioSession = mNextAudioSession;
|
||||
mAudioSessionChanged = true;
|
||||
if(!mAudioSession->mReconnect)
|
||||
{
|
||||
mNextAudioSession = NULL;
|
||||
|
|
@ -1547,6 +1563,8 @@ void LLVivoxVoiceClient::stateMachine()
|
|||
mAccountHandle.clear();
|
||||
deleteAllSessions();
|
||||
deleteAllBuddies();
|
||||
deleteVoiceFonts();
|
||||
deleteVoiceFontTemplates();
|
||||
|
||||
if(mVoiceEnabled && !mRelogRequested)
|
||||
{
|
||||
|
|
@ -1627,16 +1645,16 @@ void LLVivoxVoiceClient::stateMachine()
|
|||
|
||||
}
|
||||
|
||||
if(mAudioSession && mAudioSession->mParticipantsChanged)
|
||||
{
|
||||
mAudioSession->mParticipantsChanged = false;
|
||||
mAudioSessionChanged = true;
|
||||
}
|
||||
|
||||
if(mAudioSessionChanged)
|
||||
if (mAudioSessionChanged)
|
||||
{
|
||||
mAudioSessionChanged = false;
|
||||
notifyParticipantObservers();
|
||||
notifyVoiceFontObservers();
|
||||
}
|
||||
else if (mAudioSession && mAudioSession->mParticipantsChanged)
|
||||
{
|
||||
mAudioSession->mParticipantsChanged = false;
|
||||
notifyParticipantObservers();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1751,8 +1769,11 @@ void LLVivoxVoiceClient::sessionGroupCreateSendMessage()
|
|||
|
||||
void LLVivoxVoiceClient::sessionCreateSendMessage(sessionState *session, bool startAudio, bool startText)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL;
|
||||
|
||||
LL_DEBUGS("Voice") << "Requesting create: " << session->mSIPURI << LL_ENDL;
|
||||
|
||||
S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
|
||||
LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
|
||||
|
||||
session->mCreateInProgress = true;
|
||||
if(startAudio)
|
||||
{
|
||||
|
|
@ -1776,10 +1797,11 @@ void LLVivoxVoiceClient::sessionCreateSendMessage(sessionState *session, bool st
|
|||
<< "<Password>" << LLURI::escape(session->mHash, allowed_chars) << "</Password>"
|
||||
<< "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>";
|
||||
}
|
||||
|
||||
|
||||
stream
|
||||
<< "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
|
||||
<< "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
|
||||
<< "<VoiceFontID>" << font_index << "</VoiceFontID>"
|
||||
<< "<Name>" << mChannelName << "</Name>"
|
||||
<< "</Request>\n\n\n";
|
||||
writeString(stream.str());
|
||||
|
|
@ -1787,8 +1809,11 @@ void LLVivoxVoiceClient::sessionCreateSendMessage(sessionState *session, bool st
|
|||
|
||||
void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio, bool startText)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL;
|
||||
|
||||
LL_DEBUGS("Voice") << "Requesting create: " << session->mSIPURI << LL_ENDL;
|
||||
|
||||
S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
|
||||
LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
|
||||
|
||||
session->mCreateInProgress = true;
|
||||
if(startAudio)
|
||||
{
|
||||
|
|
@ -1814,6 +1839,7 @@ void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session
|
|||
<< "<Name>" << mChannelName << "</Name>"
|
||||
<< "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
|
||||
<< "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
|
||||
<< "<VoiceFontID>" << font_index << "</VoiceFontID>"
|
||||
<< "<Password>" << password << "</Password>"
|
||||
<< "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>"
|
||||
<< "</Request>\n\n\n"
|
||||
|
|
@ -1824,7 +1850,10 @@ void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session
|
|||
|
||||
void LLVivoxVoiceClient::sessionMediaConnectSendMessage(sessionState *session)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "connecting audio to session handle: " << session->mHandle << LL_ENDL;
|
||||
LL_DEBUGS("Voice") << "Connecting audio to session handle: " << session->mHandle << LL_ENDL;
|
||||
|
||||
S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
|
||||
LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
|
||||
|
||||
session->mMediaConnectInProgress = true;
|
||||
|
||||
|
|
@ -1834,6 +1863,7 @@ void LLVivoxVoiceClient::sessionMediaConnectSendMessage(sessionState *session)
|
|||
<< "<Request requestId=\"" << session->mHandle << "\" action=\"Session.MediaConnect.1\">"
|
||||
<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
|
||||
<< "<SessionHandle>" << session->mHandle << "</SessionHandle>"
|
||||
<< "<VoiceFontID>" << font_index << "</VoiceFontID>"
|
||||
<< "<Media>Audio</Media>"
|
||||
<< "</Request>\n\n\n";
|
||||
|
||||
|
|
@ -3156,7 +3186,7 @@ void LLVivoxVoiceClient::sessionAddedEvent(
|
|||
else
|
||||
{
|
||||
LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL;
|
||||
setUUIDFromStringHash(session->mCallerID, session->mSIPURI);
|
||||
session->mCallerID.generate(session->mSIPURI);
|
||||
session->mSynthesizedCallerID = true;
|
||||
|
||||
// Can't look up the name in this case -- we have to extract it from the URI.
|
||||
|
|
@ -4134,8 +4164,8 @@ LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParti
|
|||
else
|
||||
{
|
||||
// Create a UUID by hashing the URI, but do NOT set mAvatarIDValid.
|
||||
// This tells code in LLVivoxVoiceClient that the ID will not be in the name cache.
|
||||
setUUIDFromStringHash(result->mAvatarID, uri);
|
||||
// This indicates that the ID will not be in the name cache.
|
||||
result->mAvatarID.generate(uri);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4630,7 +4660,7 @@ BOOL LLVivoxVoiceClient::isOnlineSIP(const LLUUID &id)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool LLVivoxVoiceClient::isVoiceWorking()
|
||||
bool LLVivoxVoiceClient::isVoiceWorking() const
|
||||
{
|
||||
//Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758)
|
||||
// Condition with joining spatial num was added to take into account possible problems with connection to voice
|
||||
|
|
@ -5650,7 +5680,12 @@ LLVivoxVoiceClient::sessionState *LLVivoxVoiceClient::addSession(const std::stri
|
|||
result = new sessionState();
|
||||
result->mSIPURI = uri;
|
||||
result->mHandle = handle;
|
||||
|
||||
|
||||
if (LLVoiceClient::instance().getVoiceEffectEnabled())
|
||||
{
|
||||
result->mVoiceFontID = LLVoiceClient::instance().getVoiceEffectDefault();
|
||||
}
|
||||
|
||||
mSessions.insert(result);
|
||||
|
||||
if(!result->mHandle.empty())
|
||||
|
|
@ -6075,8 +6110,8 @@ void LLVivoxVoiceClient::notifyParticipantObservers()
|
|||
)
|
||||
{
|
||||
LLVoiceClientParticipantObserver* observer = *it;
|
||||
observer->onChange();
|
||||
// In case onChange() deleted an entry.
|
||||
observer->onParticipantsChanged();
|
||||
// In case onParticipantsChanged() deleted an entry.
|
||||
it = mParticipantObservers.upper_bound(observer);
|
||||
}
|
||||
}
|
||||
|
|
@ -6239,6 +6274,269 @@ void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string
|
|||
}
|
||||
}
|
||||
|
||||
bool LLVivoxVoiceClient::setVoiceEffect(const LLUUID& id)
|
||||
{
|
||||
if (!mAudioSession)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!id.isNull())
|
||||
{
|
||||
if (mVoiceFontMap.empty())
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Voice fonts not available." << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
else if (mVoiceFontMap.find(id) == mVoiceFontMap.end())
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Invalid voice font " << id << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// *TODO: Check for expired fonts?
|
||||
mAudioSession->mVoiceFontID = id;
|
||||
|
||||
// *TODO: Separate voice font defaults for spatial chat and IM?
|
||||
gSavedPerAccountSettings.setString("VoiceEffectDefault", id.asString());
|
||||
|
||||
sessionSetVoiceFontSendMessage(mAudioSession);
|
||||
notifyVoiceFontObservers();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const LLUUID LLVivoxVoiceClient::getVoiceEffect()
|
||||
{
|
||||
return mAudioSession ? mAudioSession->mVoiceFontID : LLUUID::null;
|
||||
}
|
||||
|
||||
LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) :
|
||||
mID(id),
|
||||
mFontIndex(0),
|
||||
mHasExpired(false),
|
||||
mFontType(VOICE_FONT_TYPE_NONE),
|
||||
mFontStatus(VOICE_FONT_STATUS_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
LLVivoxVoiceClient::voiceFontEntry::~voiceFontEntry()
|
||||
{
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::addVoiceFont(const S32 font_index,
|
||||
const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &expiration_date,
|
||||
const bool has_expired,
|
||||
const S32 font_type,
|
||||
const S32 font_status,
|
||||
const bool template_font)
|
||||
{
|
||||
// Vivox SessionFontIDs are not guaranteed to remain the same between
|
||||
// sessions or grids so use a UUID for the name.
|
||||
|
||||
// If received name is not a UUID, fudge one by hashing the name and type
|
||||
LLUUID font_id;
|
||||
if (LLUUID::validate(name))
|
||||
{
|
||||
font_id = LLUUID(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
font_id.generate(STRINGIZE(font_type << ":" << name));
|
||||
}
|
||||
|
||||
voiceFontEntry *font = NULL;
|
||||
|
||||
voice_font_map_t& font_map = template_font ? mVoiceFontTemplateMap : mVoiceFontMap;
|
||||
voice_effect_list_t& font_list = template_font ? mVoiceFontTemplateList : mVoiceFontList;
|
||||
|
||||
// Hopefully won't happen, but behave gracefully if there is a duplicate
|
||||
// by Replacing the previous one unless this one has expired.
|
||||
// *TODO: Should maybe check for the later expiry date if neither has
|
||||
// expired, and favour user fonts over root fonts? But as we shouldn't
|
||||
// have duplicates anyway, it's probably not worth the effort.
|
||||
voice_font_map_t::iterator iter = font_map.find(font_id);
|
||||
bool duplicate = (iter != font_map.end());
|
||||
if (duplicate)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Voice font " << font_index << " duplicates " << iter->second->mFontIndex << "!" << LL_ENDL;
|
||||
|
||||
if (!has_expired)
|
||||
{
|
||||
font = iter->second;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
font = new voiceFontEntry(font_id);
|
||||
}
|
||||
|
||||
if (font)
|
||||
{
|
||||
font->mFontIndex = font_index;
|
||||
// Use the description for the human readable name if available, as the
|
||||
// "name" will probably be a UUID.
|
||||
font->mName = description.empty() ? name : description;
|
||||
font->mExpirationDate = expiration_date;
|
||||
font->mHasExpired = has_expired;
|
||||
font->mFontType = font_type;
|
||||
font->mFontStatus = font_status;
|
||||
|
||||
LL_DEBUGS("Voice") << (template_font?"Template: ":"") << font_id
|
||||
<< " (" << font_index << ") : " << name << (has_expired?" (Expired)":"")
|
||||
<< LL_ENDL;
|
||||
|
||||
if (font_type < VOICE_FONT_TYPE_NONE || font_type >= VOICE_FONT_TYPE_UNKNOWN)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Unknown voice font type: " << font_type << LL_ENDL;
|
||||
}
|
||||
if (font_status < VOICE_FONT_STATUS_NONE || font_status >= VOICE_FONT_STATUS_UNKNOWN)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Unknown voice font status: " << font_status << LL_ENDL;
|
||||
}
|
||||
|
||||
if (!duplicate)
|
||||
{
|
||||
font_map.insert(voice_font_map_t::value_type(font->mID, font));
|
||||
font_list.insert(voice_effect_list_t::value_type(font->mName, font->mID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::deleteVoiceFonts()
|
||||
{
|
||||
mVoiceFontList.clear();
|
||||
|
||||
voice_font_map_t::iterator iter;
|
||||
for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter)
|
||||
{
|
||||
delete iter->second;
|
||||
}
|
||||
mVoiceFontMap.clear();
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::deleteVoiceFontTemplates()
|
||||
{
|
||||
mVoiceFontTemplateList.clear();
|
||||
|
||||
voice_font_map_t::iterator iter;
|
||||
for (iter = mVoiceFontTemplateMap.begin(); iter != mVoiceFontTemplateMap.end(); ++iter)
|
||||
{
|
||||
delete iter->second;
|
||||
}
|
||||
mVoiceFontTemplateMap.clear();
|
||||
}
|
||||
|
||||
S32 LLVivoxVoiceClient::getVoiceFontIndex(const LLUUID& id) const
|
||||
{
|
||||
S32 result = 0;
|
||||
if (!id.isNull())
|
||||
{
|
||||
voice_font_map_t::const_iterator it = mVoiceFontMap.find(id);
|
||||
if (it != mVoiceFontMap.end())
|
||||
{
|
||||
result = it->second->mFontIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Selected voice font " << id << " is not available." << LL_ENDL;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::accountGetSessionFontsSendMessage()
|
||||
{
|
||||
if(!mAccountHandle.empty())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
LL_DEBUGS("Voice") << "Requesting voice font list." << LL_ENDL;
|
||||
|
||||
stream
|
||||
<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.GetSessionFonts.1\">"
|
||||
<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
|
||||
<< "</Request>"
|
||||
<< "\n\n\n";
|
||||
|
||||
writeString(stream.str());
|
||||
}
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::accountGetTemplateFontsSendMessage()
|
||||
{
|
||||
if(!mAccountHandle.empty())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
LL_DEBUGS("Voice") << "Requesting voice font template list." << LL_ENDL;
|
||||
|
||||
stream
|
||||
<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.GetTemplateFonts.1\">"
|
||||
<< "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
|
||||
<< "</Request>"
|
||||
<< "\n\n\n";
|
||||
|
||||
writeString(stream.str());
|
||||
}
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::sessionSetVoiceFontSendMessage(sessionState *session)
|
||||
{
|
||||
S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
|
||||
LL_DEBUGS("Voice") << "Requesting voice font: " << session->mVoiceFontID << " (" << font_index << "), session handle: " << session->mHandle << LL_ENDL;
|
||||
|
||||
std::ostringstream stream;
|
||||
|
||||
stream
|
||||
<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetVoiceFont.1\">"
|
||||
<< "<SessionHandle>" << session->mHandle << "</SessionHandle>"
|
||||
<< "<SessionFontID>" << font_index << "</SessionFontID>"
|
||||
<< "</Request>\n\n\n";
|
||||
|
||||
writeString(stream.str());
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const std::string &statusString)
|
||||
{
|
||||
// Voice font list entries were updated via addVoiceFont() during parsing.
|
||||
if(getState() == stateVoiceFontsWait)
|
||||
{
|
||||
setState(stateVoiceFontsReceived);
|
||||
}
|
||||
notifyVoiceFontObservers();
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::accountGetTemplateFontsResponse(int statusCode, const std::string &statusString)
|
||||
{
|
||||
// Voice font list entries were updated via addVoiceFont() during parsing.
|
||||
notifyVoiceFontObservers();
|
||||
}
|
||||
void LLVivoxVoiceClient::addObserver(LLVoiceEffectObserver* observer)
|
||||
{
|
||||
mVoiceFontObservers.insert(observer);
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer)
|
||||
{
|
||||
mVoiceFontObservers.erase(observer);
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::notifyVoiceFontObservers()
|
||||
{
|
||||
for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin();
|
||||
it != mVoiceFontObservers.end();
|
||||
)
|
||||
{
|
||||
LLVoiceEffectObserver* observer = *it;
|
||||
observer->onVoiceEffectChanged();
|
||||
// In case onVoiceEffectChanged() deleted an entry.
|
||||
it = mVoiceFontObservers.upper_bound(observer);
|
||||
}
|
||||
}
|
||||
|
||||
LLVivoxProtocolParser::LLVivoxProtocolParser()
|
||||
{
|
||||
|
|
@ -6457,7 +6755,34 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
|
|||
{
|
||||
LLVivoxVoiceClient::getInstance()->deleteAllAutoAcceptRules();
|
||||
}
|
||||
|
||||
else if (!stricmp("SessionFonts", tag))
|
||||
{
|
||||
LLVivoxVoiceClient::getInstance()->deleteVoiceFonts();
|
||||
}
|
||||
else if (!stricmp("SessionFont", tag))
|
||||
{
|
||||
id = 0;
|
||||
nameString.clear();
|
||||
descriptionString.clear();
|
||||
expirationDateString.clear();
|
||||
hasExpired = false;
|
||||
fontType = 0;
|
||||
fontStatus = 0;
|
||||
}
|
||||
else if (!stricmp("TemplateFonts", tag))
|
||||
{
|
||||
LLVivoxVoiceClient::getInstance()->deleteVoiceFontTemplates();
|
||||
}
|
||||
else if (!stricmp("TemplateFont", tag))
|
||||
{
|
||||
id = 0;
|
||||
nameString.clear();
|
||||
descriptionString.clear();
|
||||
expirationDateString.clear();
|
||||
hasExpired = false;
|
||||
fontType = 0;
|
||||
fontStatus = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
responseDepth++;
|
||||
|
|
@ -6603,7 +6928,38 @@ void LLVivoxProtocolParser::EndTag(const char *tag)
|
|||
subscriptionHandle = string;
|
||||
else if (!stricmp("SubscriptionType", tag))
|
||||
subscriptionType = string;
|
||||
|
||||
else if (!stricmp("SessionFont", tag))
|
||||
{
|
||||
LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDateString, hasExpired, fontType, fontStatus, false);
|
||||
}
|
||||
else if (!stricmp("TemplateFont", tag))
|
||||
{
|
||||
LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDateString, hasExpired, fontType, fontStatus, true);
|
||||
}
|
||||
else if (!stricmp("ID", tag))
|
||||
{
|
||||
id = strtol(string.c_str(), NULL, 10);
|
||||
}
|
||||
else if (!stricmp("Description", tag))
|
||||
{
|
||||
descriptionString = string;
|
||||
}
|
||||
else if (!stricmp("ExpirationDate", tag))
|
||||
{
|
||||
expirationDateString = string;
|
||||
}
|
||||
else if (!stricmp("Expired", tag))
|
||||
{
|
||||
hasExpired = !stricmp(string.c_str(), "1");
|
||||
}
|
||||
else if (!stricmp("Type", tag))
|
||||
{
|
||||
fontType = strtol(string.c_str(), NULL, 10);
|
||||
}
|
||||
else if (!stricmp("Status", tag))
|
||||
{
|
||||
fontStatus = strtol(string.c_str(), NULL, 10);
|
||||
}
|
||||
|
||||
textBuffer.clear();
|
||||
accumulateText= false;
|
||||
|
|
@ -6861,6 +7217,14 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
|
|||
// We don't need to process these, but they're so spammy we don't want to log them.
|
||||
squelchDebugOutput = true;
|
||||
}
|
||||
else if (!stricmp(actionCstr, "Account.GetSessionFonts.1"))
|
||||
{
|
||||
LLVivoxVoiceClient::getInstance()->accountGetSessionFontsResponse(statusCode, statusString);
|
||||
}
|
||||
else if (!stricmp(actionCstr, "Account.GetTemplateFonts.1"))
|
||||
{
|
||||
LLVivoxVoiceClient::getInstance()->accountGetTemplateFontsResponse(statusCode, statusString);
|
||||
}
|
||||
/*
|
||||
else if (!stricmp(actionCstr, "Account.ChannelGetList.1"))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,15 +57,9 @@ class LLVivoxVoiceClientMuteListObserver;
|
|||
class LLVivoxVoiceClientFriendsObserver;
|
||||
|
||||
|
||||
class LLVivoxVoiceClientParticipantObserver
|
||||
{
|
||||
public:
|
||||
virtual ~LLVivoxVoiceClientParticipantObserver() { }
|
||||
virtual void onChange() = 0;
|
||||
};
|
||||
|
||||
|
||||
class LLVivoxVoiceClient: public LLSingleton<LLVivoxVoiceClient>, virtual public LLVoiceModuleInterface
|
||||
class LLVivoxVoiceClient : public LLSingleton<LLVivoxVoiceClient>,
|
||||
virtual public LLVoiceModuleInterface,
|
||||
virtual public LLVoiceEffectInterface
|
||||
{
|
||||
LOG_CLASS(LLVivoxVoiceClient);
|
||||
public:
|
||||
|
|
@ -84,7 +78,7 @@ public:
|
|||
virtual void updateSettings(); // call after loading settings and whenever they change
|
||||
|
||||
// Returns true if vivox has successfully logged in and is not in error state
|
||||
virtual bool isVoiceWorking();
|
||||
virtual bool isVoiceWorking() const;
|
||||
|
||||
/////////////////////
|
||||
/// @name Tuning
|
||||
|
|
@ -232,15 +226,35 @@ public:
|
|||
virtual void removeObserver(LLFriendObserver* observer);
|
||||
virtual void addObserver(LLVoiceClientParticipantObserver* observer);
|
||||
virtual void removeObserver(LLVoiceClientParticipantObserver* observer);
|
||||
|
||||
|
||||
|
||||
//@}
|
||||
|
||||
virtual std::string sipURIFromID(const LLUUID &id);
|
||||
//@}
|
||||
|
||||
|
||||
/// @name LLVoiceEffectInterface virtual implementations
|
||||
/// @see LLVoiceEffectInterface
|
||||
//@{
|
||||
|
||||
//////////////////////////
|
||||
/// @name Accessors
|
||||
//@{
|
||||
virtual bool setVoiceEffect(const LLUUID& id);
|
||||
virtual const LLUUID getVoiceEffect();
|
||||
|
||||
virtual const voice_effect_list_t &getVoiceEffectList() const { return mVoiceFontList; };
|
||||
virtual const voice_effect_list_t &getVoiceEffectTemplateList() const { return mVoiceFontTemplateList; };
|
||||
//@}
|
||||
|
||||
//////////////////////////////
|
||||
/// @name Status notification
|
||||
//@{
|
||||
virtual void addObserver(LLVoiceEffectObserver* observer);
|
||||
virtual void removeObserver(LLVoiceEffectObserver* observer);
|
||||
//@}
|
||||
|
||||
//@}
|
||||
|
||||
|
||||
protected:
|
||||
//////////////////////
|
||||
// Vivox Specific definitions
|
||||
|
|
@ -278,14 +292,13 @@ protected:
|
|||
bool mIsSpeaking;
|
||||
bool mIsModeratorMuted;
|
||||
bool mOnMuteList; // true if this avatar is on the user's mute list (and should be muted)
|
||||
bool mVolumeSet; // true if incoming volume messages should not change the volume
|
||||
bool mVolumeSet; // true if incoming volume messages should not change the volume
|
||||
bool mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed)
|
||||
bool mAvatarIDValid;
|
||||
bool mIsSelf;
|
||||
};
|
||||
|
||||
typedef std::map<const std::string, participantState*> participantMap;
|
||||
|
||||
typedef std::map<const LLUUID, participantState*> participantUUIDMap;
|
||||
|
||||
struct sessionState
|
||||
|
|
@ -332,14 +345,17 @@ protected:
|
|||
bool mIncoming;
|
||||
bool mVoiceEnabled;
|
||||
bool mReconnect; // Whether we should try to reconnect to this session if it's dropped
|
||||
// Set to true when the mute state of someone in the participant list changes.
|
||||
|
||||
// Set to true when the volume/mute state of someone in the participant list changes.
|
||||
// The code will have to walk the list to find the changed participant(s).
|
||||
bool mVolumeDirty;
|
||||
bool mMuteDirty;
|
||||
|
||||
bool mMuteDirty;
|
||||
|
||||
bool mParticipantsChanged;
|
||||
participantMap mParticipantsByURI;
|
||||
participantUUIDMap mParticipantsByUUID;
|
||||
|
||||
LLUUID mVoiceFontID;
|
||||
};
|
||||
|
||||
// internal state for a simple state machine. This is used to deal with the asynchronous nature of some of the messages.
|
||||
|
|
@ -364,6 +380,8 @@ protected:
|
|||
stateNeedsLogin, // send login request
|
||||
stateLoggingIn, // waiting for account handle
|
||||
stateLoggedIn, // account handle received
|
||||
stateVoiceFontsWait, // Awaiting the list of voice fonts
|
||||
stateVoiceFontsReceived, // List of voice fonts received
|
||||
stateCreatingSessionGroup, // Creating the main session group
|
||||
stateNoChannel, //
|
||||
stateJoiningSession, // waiting for session handle
|
||||
|
|
@ -591,8 +609,8 @@ protected:
|
|||
void deleteAllAutoAcceptRules(void);
|
||||
void addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy);
|
||||
void accountListBlockRulesResponse(int statusCode, const std::string &statusString);
|
||||
void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString);
|
||||
|
||||
void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString);
|
||||
|
||||
/////////////////////////////
|
||||
// session control messages
|
||||
|
||||
|
|
@ -621,7 +639,21 @@ protected:
|
|||
void lookupName(const LLUUID &id);
|
||||
static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
|
||||
void avatarNameResolved(const LLUUID &id, const std::string &name);
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// Voice fonts
|
||||
|
||||
void addVoiceFont(const S32 id,
|
||||
const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &expiration_date,
|
||||
const bool has_expired,
|
||||
const S32 font_type,
|
||||
const S32 font_status,
|
||||
const bool template_font = false);
|
||||
void accountGetSessionFontsResponse(int statusCode, const std::string &statusString);
|
||||
void accountGetTemplateFontsResponse(int statusCode, const std::string &statusString);
|
||||
|
||||
private:
|
||||
LLVoiceVersionInfo mVoiceVersion;
|
||||
|
||||
|
|
@ -804,6 +836,59 @@ private:
|
|||
typedef std::set<LLFriendObserver*> friend_observer_set_t;
|
||||
friend_observer_set_t mFriendObservers;
|
||||
void notifyFriendObservers();
|
||||
|
||||
// Voice Fonts
|
||||
|
||||
void deleteVoiceFonts();
|
||||
void deleteVoiceFontTemplates();
|
||||
|
||||
S32 getVoiceFontIndex(const LLUUID& id) const;
|
||||
|
||||
void accountGetSessionFontsSendMessage();
|
||||
void accountGetTemplateFontsSendMessage();
|
||||
void sessionSetVoiceFontSendMessage(sessionState *session);
|
||||
|
||||
void notifyVoiceFontObservers();
|
||||
|
||||
typedef enum e_voice_font_type
|
||||
{
|
||||
VOICE_FONT_TYPE_NONE = 0,
|
||||
VOICE_FONT_TYPE_ROOT = 1,
|
||||
VOICE_FONT_TYPE_USER = 2,
|
||||
VOICE_FONT_TYPE_UNKNOWN
|
||||
} EVoiceFontType;
|
||||
|
||||
typedef enum e_voice_font_status
|
||||
{
|
||||
VOICE_FONT_STATUS_NONE = 0,
|
||||
VOICE_FONT_STATUS_FREE = 1,
|
||||
VOICE_FONT_STATUS_NOT_FREE = 2,
|
||||
VOICE_FONT_STATUS_UNKNOWN
|
||||
} EVoiceFontStatus;
|
||||
|
||||
struct voiceFontEntry
|
||||
{
|
||||
voiceFontEntry(LLUUID& id);
|
||||
~voiceFontEntry();
|
||||
|
||||
LLUUID mID;
|
||||
S32 mFontIndex;
|
||||
std::string mName;
|
||||
std::string mExpirationDate;
|
||||
bool mHasExpired;
|
||||
S32 mFontType;
|
||||
S32 mFontStatus;
|
||||
};
|
||||
|
||||
voice_effect_list_t mVoiceFontList;
|
||||
voice_effect_list_t mVoiceFontTemplateList;
|
||||
|
||||
typedef std::map<const LLUUID, voiceFontEntry*> voice_font_map_t;
|
||||
voice_font_map_t mVoiceFontMap;
|
||||
voice_font_map_t mVoiceFontTemplateMap;
|
||||
|
||||
typedef std::set<LLVoiceEffectObserver*> voice_font_observer_set_t;
|
||||
voice_font_observer_set_t mVoiceFontObservers;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -890,7 +975,12 @@ protected:
|
|||
int numberOfAliases;
|
||||
std::string subscriptionHandle;
|
||||
std::string subscriptionType;
|
||||
|
||||
S32 id;
|
||||
std::string descriptionString;
|
||||
std::string expirationDateString;
|
||||
bool hasExpired;
|
||||
S32 fontType;
|
||||
S32 fontStatus;
|
||||
|
||||
// Members for processing text between tags
|
||||
std::string textBuffer;
|
||||
|
|
@ -913,5 +1003,3 @@ protected:
|
|||
|
||||
#endif //LL_VIVOX_VOICE_CLIENT_H
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
can_resize="true"
|
||||
can_minimize="true"
|
||||
can_close="false"
|
||||
height="202"
|
||||
height="205"
|
||||
layout="topleft"
|
||||
min_height="124"
|
||||
min_width="190"
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
user_resize="false"
|
||||
auto_resize="false"
|
||||
layout="topleft"
|
||||
height="26"
|
||||
height="20"
|
||||
name="my_panel">
|
||||
<avatar_icon
|
||||
enabled="false"
|
||||
|
|
@ -86,23 +86,38 @@
|
|||
visible="true"
|
||||
width="20" />
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
user_resize="false"
|
||||
follows="top|left"
|
||||
height="26"
|
||||
visible="true"
|
||||
layout="topleft"
|
||||
name="leave_call_btn_panel"
|
||||
width="100">
|
||||
<button
|
||||
follows="right|top"
|
||||
height="23"
|
||||
top_pad="0"
|
||||
label="Leave Call"
|
||||
name="leave_call_btn"
|
||||
width="100" />
|
||||
</layout_panel>
|
||||
<layout_stack
|
||||
clip="true"
|
||||
auto_resize="false"
|
||||
follows="left|top|right"
|
||||
height="26"
|
||||
layout="topleft"
|
||||
mouse_opaque="false"
|
||||
name="voice_effect_and_leave_call_stack"
|
||||
orientation="horizontal"
|
||||
width="262">
|
||||
<panel
|
||||
class="panel_voice_effect"
|
||||
name="panel_voice_effect"
|
||||
visiblity_control="VoiceEffectEnabled"
|
||||
filename="panel_voice_effect.xml" />
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
user_resize="false"
|
||||
follows="top|right"
|
||||
height="23"
|
||||
visible="true"
|
||||
layout="topleft"
|
||||
name="leave_call_btn_panel"
|
||||
width="100">
|
||||
<button
|
||||
follows="right|top"
|
||||
height="23"
|
||||
label="Leave Call"
|
||||
name="leave_call_btn"
|
||||
width="100" />
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
<layout_panel
|
||||
follows="all"
|
||||
layout="topleft"
|
||||
|
|
|
|||
Loading…
Reference in New Issue