summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorAimee Linden <aimee@lindenlab.com>2010-04-28 03:33:39 +0100
committerAimee Linden <aimee@lindenlab.com>2010-04-28 03:33:39 +0100
commitad24d0c72a272dd9b30841ecc20e34d334e6f2b6 (patch)
treebe61cfeea38ac280ca0332a002bc5f13f81d4106 /indra/newview
parentfbc0e795b114ddbfb73cc62ce25a1e9a1cafacba (diff)
parentcacfa18643092547e7665b36d482ad9c8c5dfc54 (diff)
Automated merge with ssh://hg.lindenlab.com/q/viewer-trunk
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/logcontrol.xml1
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/llcallfloater.cpp57
-rw-r--r--indra/newview/llcallfloater.h29
-rw-r--r--indra/newview/llparticipantlist.cpp2
-rw-r--r--indra/newview/llspeakingindicatormanager.cpp4
-rw-r--r--indra/newview/llvoicechannel.cpp6
-rw-r--r--indra/newview/llvoicechannel.h2
-rw-r--r--indra/newview/llvoiceclient.cpp360
-rw-r--r--indra/newview/llvoiceclient.h99
-rw-r--r--indra/newview/skins/default/xui/en/floater_voice_controls.xml42
11 files changed, 549 insertions, 64 deletions
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index d7bb64ce8a..d3fb958638 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -40,6 +40,7 @@
</array>
<key>tags</key>
<array>
+ <string>Voice</string>
</array>
</map>
</array>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a6dbe00759..e763f9cebc 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10405,6 +10405,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>VoiceFontDefault</key>
+ <map>
+ <key>Comment</key>
+ <string>Selected voice font</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>AutoDisengageMic</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp
index 5a96613870..703c7dd435 100644
--- a/indra/newview/llcallfloater.cpp
+++ b/indra/newview/llcallfloater.cpp
@@ -52,6 +52,7 @@
#include "lltransientfloatermgr.h"
#include "llviewerwindow.h"
#include "llvoicechannel.h"
+#include "llvoiceclient.h" // for Voice font list types
#include "llviewerparcelmgr.h"
static void get_voice_participants_uuids(uuid_vec_t& speakers_uuids);
@@ -95,7 +96,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)
@@ -105,6 +106,7 @@ LLCallFloater::LLCallFloater(const LLSD& key)
, mNonAvatarCaller(NULL)
, mVoiceType(VC_LOCAL_CHAT)
, mAgentPanel(NULL)
+, mVoiceFont(NULL)
, mSpeakingIndicator(NULL)
, mIsModeratorMutedVoice(false)
, mInitParticipantsVoiceState(false)
@@ -113,7 +115,8 @@ 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(dynamic_cast<LLVoiceClientParticipantObserver*>(this));
+ LLVoiceClient::instance().addObserver(dynamic_cast<LLVoiceClientFontsObserver*>(this));
LLTransientFloaterMgr::getInstance()->addControlView(this);
// force docked state since this floater doesn't save it between recreations
@@ -133,7 +136,8 @@ LLCallFloater::~LLCallFloater()
if(LLVoiceClient::instanceExists())
{
- LLVoiceClient::instance().removeObserver(this);
+ LLVoiceClient::instance().removeObserver(dynamic_cast<LLVoiceClientParticipantObserver*>(this));
+ LLVoiceClient::instance().removeObserver(dynamic_cast<LLVoiceClientFontsObserver*>(this));
}
LLTransientFloaterMgr::getInstance()->removeControlView(this);
}
@@ -147,6 +151,9 @@ BOOL LLCallFloater::postBuild()
childSetAction("leave_call_btn", boost::bind(&LLCallFloater::leaveCall, this));
+ mVoiceFont = getChild<LLComboBox>("voice_font");
+ childSetCommitCallback("voice_font", commitVoiceFont, this); // *FIX: childSetCommitCallback deprecated
+
mNonAvatarCaller = getChild<LLNonAvatarCaller>("non_avatar_caller");
mNonAvatarCaller->setVisible(FALSE);
@@ -158,7 +165,6 @@ BOOL LLCallFloater::postBuild()
initAgentData();
-
connectToChannel(LLVoiceChannel::getCurrentVoiceChannel());
setIsChrome(true);
@@ -204,7 +210,7 @@ void LLCallFloater::draw()
}
// virtual
-void LLCallFloater::onChange()
+void LLCallFloater::onParticipantsChanged()
{
if (NULL == mParticipants) return;
@@ -219,6 +225,31 @@ void LLCallFloater::onChange()
}
}
+// virtual
+void LLCallFloater::onVoiceFontsChanged()
+{
+ if (mVoiceFont)
+ {
+ mVoiceFont->removeall();
+ mVoiceFont->add(getString("no_voice_font"), LLUUID::null);
+
+ if (LLVoiceClient::instance().hasVoiceFonts())
+ {
+ const LLVoiceClient::voice_font_list_t font_list = LLVoiceClient::instance().getVoiceFontList();
+ for (LLVoiceClient::voice_font_list_t::const_iterator it = font_list.begin(); it != font_list.end(); ++it)
+ {
+ mVoiceFont->add(*(it->first), *(it->second), ADD_BOTTOM);
+ }
+ mVoiceFont->setEnabled(true);
+ mVoiceFont->setValue(LLVoiceClient::instance().getVoiceFont());
+ }
+ else
+ {
+ mVoiceFont->setEnabled(false);
+ }
+ }
+}
+
//////////////////////////////////////////////////////////////////////////
/// PRIVATE SECTION
//////////////////////////////////////////////////////////////////////////
@@ -232,6 +263,12 @@ void LLCallFloater::leaveCall()
}
}
+/* static */
+void LLCallFloater::commitVoiceFont(LLUICtrl* ctrl, void* userdata)
+{
+ LLVoiceClient::getInstance()->setVoiceFont(ctrl->getValue());
+}
+
void LLCallFloater::updateSession()
{
LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel();
@@ -296,7 +333,7 @@ void LLCallFloater::updateSession()
}
updateTitle();
-
+
//hide "Leave Call" button for nearby chat
bool is_local_chat = mVoiceType == VC_LOCAL_CHAT;
childSetVisible("leave_call_btn_panel", !is_local_chat);
@@ -370,7 +407,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");
@@ -718,9 +755,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());
}
@@ -740,7 +777,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();
diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h
index 0a8ea7de39..160eff312c 100644
--- a/indra/newview/llcallfloater.h
+++ b/indra/newview/llcallfloater.h
@@ -40,6 +40,7 @@
class LLAvatarList;
class LLAvatarListItem;
+class LLComboBox;
class LLNonAvatarCaller;
class LLOutputMonitorCtrl;
class LLParticipantList;
@@ -47,17 +48,19 @@ 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
+class LLCallFloater : public LLTransientDockableFloater,
+ LLVoiceClientParticipantObserver,
+ LLVoiceClientFontsObserver
{
public:
@@ -75,7 +78,10 @@ public:
*
* Refreshes list to display participants not in voice as disabled.
*/
- /*virtual*/ void onChange();
+ /*virtual*/ void onParticipantsChanged();
+
+ /// Called by LLVoiceClient::notifyVoiceFontObservers when voice font list is changed.
+ /*virtual*/ void onVoiceFontsChanged();
static void sOnCurrentChannelChanged(const LLUUID& session_id);
@@ -101,6 +107,8 @@ private:
void leaveCall();
+ static void commitVoiceFont(LLUICtrl*,void* userdata);
+
/**
* Updates mSpeakerManager and list according to current Voice Channel
*
@@ -230,6 +238,7 @@ private:
LLNonAvatarCaller* mNonAvatarCaller;
EVoiceControls mVoiceType;
LLPanel* mAgentPanel;
+ LLComboBox* mVoiceFont;
LLOutputMonitorCtrl* mSpeakingIndicator;
bool mIsModeratorMutedVoice;
@@ -259,7 +268,7 @@ private:
*
* @see sOnCurrentChannelChanged()
*/
- static LLVoiceChannel* sCurrentVoiceCanel;
+ static LLVoiceChannel* sCurrentVoiceChannel;
/* virtual */
LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::IM; }
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index c3748ca81d..d0c882e16e 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -92,7 +92,7 @@ public:
mAvalineCallers.insert(avaline_caller_id);
}
- void onChange()
+ void onParticipantsChanged()
{
uuid_set_t participant_uuids;
LLVoiceClient::getInstance()->getParticipantsUUIDSet(participant_uuids);
diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp
index cc06179481..70028dc21b 100644
--- a/indra/newview/llspeakingindicatormanager.cpp
+++ b/indra/newview/llspeakingindicatormanager.cpp
@@ -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;
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index 7bb1006e93..9ab0bf9552 100644
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -887,9 +887,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));
}
diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h
index 941cccacc3..5236b11853 100644
--- a/indra/newview/llvoicechannel.h
+++ b/indra/newview/llvoicechannel.h
@@ -112,7 +112,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;
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 298ce3fcec..d131285512 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -73,15 +73,11 @@
#include "llvoavatarself.h"
#include "llvoicechannel.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
static bool sConnectingToAgni = false;
@@ -116,14 +112,6 @@ const int MAX_LOGIN_RETRIES = 12;
// blocked is VERY rare and it's better to sacrifice response time in this situation for the sake of stability.
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.
@@ -254,6 +242,12 @@ protected:
std::string audioMediaString;
std::string displayNameString;
std::string deviceString;
+ S32 id;
+ std::string descriptionString;
+ std::string expirationDateString;
+ bool hasExpired;
+ S32 fontType;
+ S32 fontStatus;
int participantType;
bool isLocallyMuted;
bool isModeratorMuted;
@@ -511,7 +505,20 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
{
gVoiceClient->deleteAllAutoAcceptRules();
}
-
+ else if (!stricmp("SessionFonts", tag))
+ {
+ LLVoiceClient::getInstance()->deleteAllVoiceFonts();
+ }
+ else if (!stricmp("SessionFont", tag))
+ {
+ id = 0;
+ nameString.clear();
+ descriptionString.clear();
+ expirationDateString.clear();
+ hasExpired = false;
+ fontType = 0;
+ fontStatus = 0;
+ }
}
}
responseDepth++;
@@ -639,6 +646,34 @@ void LLVivoxProtocolParser::EndTag(const char *tag)
autoAcceptMask = string;
else if (!stricmp("AutoAddAsBuddy", tag))
autoAddAsBuddy = string;
+ else if (!stricmp("SessionFont", tag))
+ {
+ LLVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDateString, hasExpired, fontType, fontStatus);
+ }
+ 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);
+ }
else if (!stricmp("MessageHeader", tag))
messageHeader = string;
else if (!stricmp("MessageBody", tag))
@@ -909,6 +944,10 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
{
gVoiceClient->accountListAutoAcceptRulesResponse(statusCode, statusString);
}
+ else if (!stricmp(actionCstr, "Account.GetSessionFonts.1"))
+ {
+ LLVoiceClient::getInstance()->accountGetSessionFontsResponse(statusCode, statusString);
+ }
else if (!stricmp(actionCstr, "Session.Set3DPosition.1"))
{
// We don't need to process these, but they're so spammy we don't want to log them.
@@ -1337,6 +1376,7 @@ LLVoiceClient::LLVoiceClient() :
mBuddyListMapPopulated(false),
mBlockRulesListReceived(false),
mAutoAcceptRulesListReceived(false),
+
mCaptureDeviceDirty(false),
mRenderDeviceDirty(false),
mSpatialCoordsDirty(false),
@@ -1675,6 +1715,8 @@ std::string LLVoiceClient::state2string(LLVoiceClient::state inState)
CASE(stateNeedsLogin);
CASE(stateLoggingIn);
CASE(stateLoggedIn);
+ CASE(stateVoiceFontsWait);
+ CASE(stateVoiceFontsReceived);
CASE(stateCreatingSessionGroup);
CASE(stateNoChannel);
CASE(stateJoiningSession);
@@ -1816,7 +1858,8 @@ void LLVoiceClient::stateMachine()
// Clean up and reset everything.
closeSocket();
deleteAllSessions();
- deleteAllBuddies();
+ deleteAllBuddies();
+ deleteAllVoiceFonts();
mConnectorHandle.clear();
mAccountHandle.clear();
@@ -2250,6 +2293,10 @@ void LLVoiceClient::stateMachine()
notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
+ // request the set of available voice fonts
+ setState(stateVoiceFontsWait);
+ accountGetSessionFontsSendMessage();
+
// request the current set of block rules (we'll need them when updating the friends list)
accountListBlockRulesSendMessage();
@@ -2281,12 +2328,21 @@ void LLVoiceClient::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);
@@ -2574,6 +2630,7 @@ void LLVoiceClient::stateMachine()
mAccountHandle.clear();
deleteAllSessions();
deleteAllBuddies();
+ deleteAllVoiceFonts();
if(mVoiceEnabled && !mRelogRequested)
{
@@ -2757,6 +2814,24 @@ void LLVoiceClient::accountListAutoAcceptRulesSendMessage()
}
}
+void LLVoiceClient::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 LLVoiceClient::sessionGroupCreateSendMessage()
{
if(!mAccountHandle.empty())
@@ -2779,7 +2854,10 @@ void LLVoiceClient::sessionGroupCreateSendMessage()
void LLVoiceClient::sessionCreateSendMessage(sessionState *session, bool startAudio, bool startText)
{
LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL;
-
+
+ S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
+ LL_DEBUGS("Voice") << "Requesting voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
+
session->mCreateInProgress = true;
if(startAudio)
{
@@ -2803,10 +2881,11 @@ void LLVoiceClient::sessionCreateSendMessage(sessionState *session, bool startAu
<< "<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());
@@ -2815,7 +2894,10 @@ void LLVoiceClient::sessionCreateSendMessage(sessionState *session, bool startAu
void LLVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio, bool startText)
{
LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL;
-
+
+ S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
+ LL_DEBUGS("Voice") << "Requesting voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
+
session->mCreateInProgress = true;
if(startAudio)
{
@@ -2841,6 +2923,7 @@ void LLVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session, boo
<< "<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"
@@ -2853,6 +2936,9 @@ void LLVoiceClient::sessionMediaConnectSendMessage(sessionState *session)
{
LL_DEBUGS("Voice") << "connecting audio to session handle: " << session->mHandle << LL_ENDL;
+ S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
+ LL_DEBUGS("Voice") << "Requesting voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
+
session->mMediaConnectInProgress = true;
std::ostringstream stream;
@@ -2861,6 +2947,7 @@ void LLVoiceClient::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";
@@ -2882,6 +2969,22 @@ void LLVoiceClient::sessionTextConnectSendMessage(sessionState *session)
writeString(stream.str());
}
+void LLVoiceClient::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 LLVoiceClient::sessionTerminate()
{
mSessionTerminateRequested = true;
@@ -4171,7 +4274,7 @@ void LLVoiceClient::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.
@@ -5150,8 +5253,8 @@ LLVoiceClient::participantState *LLVoiceClient::sessionState::addParticipant(con
else
{
// Create a UUID by hashing the URI, but do NOT set mAvatarIDValid.
- // This tells code in LLVoiceClient 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);
}
}
@@ -6538,6 +6641,7 @@ LLVoiceClient::sessionState::sessionState() :
mMuteDirty(false),
mParticipantsChanged(false)
{
+ mVoiceFontID = LLUUID(gSavedSettings.getString("VoiceFontDefault"));
}
LLVoiceClient::sessionState::~sessionState()
@@ -7050,6 +7154,177 @@ void LLVoiceClient::addAutoAcceptRule(const std::string &autoAcceptMask, const s
}
}
+LLVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) :
+ mID(id),
+ mFontIndex(0),
+ mHasExpired(false),
+ mFontType(VOICE_FONT_TYPE_NONE),
+ mFontStatus(VOICE_FONT_STATUS_NONE)
+{
+}
+
+LLVoiceClient::voiceFontEntry::~voiceFontEntry()
+{
+}
+
+void LLVoiceClient::deleteAllVoiceFonts()
+{
+ mVoiceFontList.clear();
+
+ voice_font_map_t::iterator iter;
+ for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter)
+ {
+ delete iter->second;
+ }
+ mVoiceFontMap.clear();
+}
+
+void LLVoiceClient::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)
+{
+ // 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;
+
+ // 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 = mVoiceFontMap.find(&font_id);
+ bool duplicate = (iter != mVoiceFontMap.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") << "Adding voice font : " << 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)
+ {
+ mVoiceFontMap.insert(voice_font_map_t::value_type(&(font->mID), font));
+ mVoiceFontList.insert(voice_font_list_t::value_type(&(font->mName), &(font->mID)));
+ }
+ }
+}
+
+bool LLVoiceClient::setVoiceFont(const LLUUID& id)
+{
+ if (!mAudioSession || !mAudioSession->mVoiceEnabled || !hasVoiceFonts())
+ {
+ LL_DEBUGS("Voice") << "Voice fonts not available." << LL_ENDL;
+ return false;
+ }
+
+ if (id.isNull() || (mVoiceFontMap.find(&id) != mVoiceFontMap.end()))
+ {
+ // *TODO: Check for expired fonts?
+ mAudioSession->mVoiceFontID = id;
+
+ // *TODO: Separate voice font defaults for spatial chat and IM?
+ gSavedSettings.setString("VoiceFontDefault", id.asString());
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Invalid voice font " << id << LL_ENDL;
+ return false;
+ }
+
+ sessionSetVoiceFontSendMessage(mAudioSession);
+ notifyVoiceFontObservers();
+ return true;
+}
+
+const LLUUID LLVoiceClient::getVoiceFont()
+{
+ if (mAudioSession)
+ {
+ return getVoiceFont(mAudioSession->mHandle);
+ }
+ else
+ {
+ return LLUUID::null;
+ }
+}
+
+const LLUUID LLVoiceClient::getVoiceFont(const std::string &session_handle)
+{
+ LLUUID result;
+ if (hasVoiceFonts())
+ {
+ sessionState *session = findSession(session_handle);
+ if (session)
+ {
+ result = mAudioSession->mVoiceFontID;
+ }
+ }
+ return result;
+}
+
+S32 LLVoiceClient::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 LLVoiceClient::accountListBlockRulesResponse(int statusCode, const std::string &statusString)
{
// Block list entries were updated via addBlockRule() during parsing. Just flag that we're done.
@@ -7062,6 +7337,16 @@ void LLVoiceClient::accountListAutoAcceptRulesResponse(int statusCode, const std
mAutoAcceptRulesListReceived = true;
}
+void LLVoiceClient::accountGetSessionFontsResponse(int statusCode, const std::string &statusString)
+{
+ // Voice font list entries were updated via addVoiceFont() during parsing.
+ if(getState() == stateVoiceFontsWait)
+ {
+ setState(stateVoiceFontsReceived);
+ }
+ notifyVoiceFontObservers();
+}
+
void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
{
mParticipantObservers.insert(observer);
@@ -7079,12 +7364,35 @@ void LLVoiceClient::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);
}
}
+void LLVoiceClient::addObserver(LLVoiceClientFontsObserver* observer)
+{
+ mVoiceFontObservers.insert(observer);
+}
+
+void LLVoiceClient::removeObserver(LLVoiceClientFontsObserver* observer)
+{
+ mVoiceFontObservers.erase(observer);
+}
+
+void LLVoiceClient::notifyVoiceFontObservers()
+{
+ for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin();
+ it != mVoiceFontObservers.end();
+ )
+ {
+ LLVoiceClientFontsObserver* observer = *it;
+ observer->onVoiceFontsChanged();
+ // In case onVoiceFontsChanged() deleted an entry.
+ it = mVoiceFontObservers.upper_bound(observer);
+ }
+}
+
void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
{
mStatusObservers.insert(observer);
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index a29c386182..a1083652aa 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -49,7 +49,14 @@ class LLVoiceClientParticipantObserver
{
public:
virtual ~LLVoiceClientParticipantObserver() { }
- virtual void onChange() = 0;
+ virtual void onParticipantsChanged() = 0;
+};
+
+class LLVoiceClientFontsObserver
+{
+public:
+ virtual ~LLVoiceClientFontsObserver() { }
+ virtual void onVoiceFontsChanged() = 0;
};
class LLVoiceClientStatusObserver
@@ -358,6 +365,8 @@ static void updatePosition(void);
bool mParticipantsChanged;
participantMap mParticipantsByURI;
participantUUIDMap mParticipantsByUUID;
+
+ LLUUID mVoiceFontID;
};
participantState *findParticipantByID(const LLUUID& id);
@@ -429,8 +438,28 @@ static void updatePosition(void);
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);
+
+ /////////////////////////////
+ // Voice Fonts
+ bool hasVoiceFonts() const { return !mVoiceFontMap.empty(); };
+ bool setVoiceFont(const LLUUID& id);
+ const LLUUID getVoiceFont();
+ const LLUUID getVoiceFont(const std::string &session_handle);
+
+ typedef std::multimap<const std::string*, const LLUUID*, stringMapComparitor> voice_font_list_t;
+
+ const voice_font_list_t &getVoiceFontList() const { return mVoiceFontList; };
+
+ 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);
+ void accountGetSessionFontsResponse(int statusCode, const std::string &statusString);
+
/////////////////////////////
// session control messages
void connectorCreate();
@@ -452,12 +481,15 @@ static void updatePosition(void);
void accountListBlockRulesSendMessage();
void accountListAutoAcceptRulesSendMessage();
-
+
+ void accountGetSessionFontsSendMessage();
+
void sessionGroupCreateSendMessage();
void sessionCreateSendMessage(sessionState *session, bool startAudio = true, bool startText = false);
void sessionGroupAddSessionSendMessage(sessionState *session, bool startAudio = true, bool startText = false);
void sessionMediaConnectSendMessage(sessionState *session); // just joins the audio session
void sessionTextConnectSendMessage(sessionState *session); // just joins the text session
+ void sessionSetVoiceFontSendMessage(sessionState *session);
void sessionTerminateSendMessage(sessionState *session);
void sessionGroupTerminateSendMessage(sessionState *session);
void sessionMediaDisconnectSendMessage(sessionState *session);
@@ -475,6 +507,9 @@ static void updatePosition(void);
void addObserver(LLVoiceClientParticipantObserver* observer);
void removeObserver(LLVoiceClientParticipantObserver* observer);
+ void addObserver(LLVoiceClientFontsObserver* observer);
+ void removeObserver(LLVoiceClientFontsObserver* observer);
+
void addObserver(LLVoiceClientStatusObserver* observer);
void removeObserver(LLVoiceClientStatusObserver* observer);
@@ -489,7 +524,7 @@ static void updatePosition(void);
deviceList *getCaptureDevices();
deviceList *getRenderDevices();
-
+
void setNonSpatialChannel(
const std::string &uri,
const std::string &credentials);
@@ -562,6 +597,8 @@ static void updatePosition(void);
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
@@ -662,7 +699,48 @@ static void updatePosition(void);
bool mBlockRulesListReceived;
bool mAutoAcceptRulesListReceived;
buddyListMap mBuddyListMap;
-
+
+ // Voice Fonts
+
+ S32 getVoiceFontIndex(const LLUUID& id) const;
+ void deleteAllVoiceFonts();
+
+ 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;
+ };
+ typedef std::map<const LLUUID*, voiceFontEntry*, uuidMapComparitor> voice_font_map_t;
+
+ voice_font_map_t mVoiceFontMap;
+ voice_font_list_t mVoiceFontList;
+
+ // Audio devices
+
deviceList mCaptureDevices;
deviceList mRenderDevices;
@@ -674,8 +752,8 @@ static void updatePosition(void);
// This should be called when the code detects we have changed parcels.
// It initiates the call to the server that gets the parcel channel.
void parcelChanged();
-
- void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
+
+ void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
void joinSession(sessionState *session);
static std::string nameFromAvatar(LLVOAvatar *avatar);
@@ -764,6 +842,11 @@ static std::string nameFromsipURI(const std::string &uri);
void notifyParticipantObservers();
+ typedef std::set<LLVoiceClientFontsObserver*> voice_font_observer_set_t;
+ voice_font_observer_set_t mVoiceFontObservers;
+
+ void notifyVoiceFontObservers();
+
typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t;
status_observer_set_t mStatusObservers;
diff --git a/indra/newview/skins/default/xui/en/floater_voice_controls.xml b/indra/newview/skins/default/xui/en/floater_voice_controls.xml
index 5b77f11d71..885c8304eb 100644
--- a/indra/newview/skins/default/xui/en/floater_voice_controls.xml
+++ b/indra/newview/skins/default/xui/en/floater_voice_controls.xml
@@ -35,6 +35,9 @@
name="no_one_near">
No one near has voice enabled
</string>
+ <floater.string name="no_voice_font">
+ No Voice Effect
+ </floater.string>
<layout_stack
clip="false"
follows="all"
@@ -86,23 +89,56 @@
visible="true"
width="20" />
</layout_panel>
- <layout_panel
+ <layout_stack
+ clip="false"
+ auto_resize="false"
+ follows="left|right"
+ height="23"
+ layout="topleft"
+ left="10"
+ mouse_opaque="false"
+ name="voice_font_and_leave_call_stack"
+ orientation="horizontal"
+ width="263">
+ <layout_panel
+ auto_resize="true"
+ user_resize="false"
+ follows="top|left"
+ height="26"
+ visible="true"
+ layout="topleft"
+ name="voice_font_panel"
+ width="150">
+ <combo_box
+ follows="left|top|right"
+ height="23"
+ name="voice_font"
+ top_pad="0"
+ width="150">
+ <combo_box.item
+ label="No Voice Effect"
+ name="no_voice_font"
+ value="0" />
+ </combo_box>
+ </layout_panel>
+ <layout_panel
auto_resize="false"
user_resize="false"
- follows="top|left"
+ follows="top|right"
height="26"
visible="true"
layout="topleft"
name="leave_call_btn_panel"
width="100">
<button
- follows="right|top"
+ follows="right|top"
height="23"
top_pad="0"
label="Leave Call"
name="leave_call_btn"
width="100" />
</layout_panel>
+ </layout_stack>
<layout_panel
follows="all"
layout="topleft"