summaryrefslogtreecommitdiff
path: root/indra/newview/llvoicevivox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvoicevivox.cpp')
-rw-r--r--indra/newview/llvoicevivox.cpp779
1 files changed, 734 insertions, 45 deletions
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index bcb1a70efb..7daf865151 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -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),
@@ -348,10 +337,13 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() :
mVoiceEnabled(false),
mWriteInProgress(false),
- mLipSyncEnabled(false)
-
+ mLipSyncEnabled(false),
+ mVoiceFontsReceived(false),
+ mVoiceFontsNew(false),
+ mCaptureBufferRecording(false),
+ mCaptureBufferPlaying(false)
{
mSpeakerVolume = scale_speaker_volume(0);
@@ -654,6 +646,11 @@ std::string LLVivoxVoiceClient::state2string(LLVivoxVoiceClient::state inState)
CASE(stateMicTuningStart);
CASE(stateMicTuningRunning);
CASE(stateMicTuningStop);
+ CASE(stateCaptureBufferPaused);
+ CASE(stateCaptureBufferRecStart);
+ CASE(stateCaptureBufferRecording);
+ CASE(stateCaptureBufferPlayStart);
+ CASE(stateCaptureBufferPlaying);
CASE(stateConnectorStart);
CASE(stateConnectorStarting);
CASE(stateConnectorStarted);
@@ -662,6 +659,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 +774,10 @@ void LLVivoxVoiceClient::stateMachine()
// Clean up and reset everything.
closeSocket();
deleteAllSessions();
- deleteAllBuddies();
-
+ deleteAllBuddies();
+ deleteVoiceFonts();
+ deleteVoiceFontTemplates();
+
mConnectorHandle.clear();
mAccountHandle.clear();
mAccountPassword.clear();
@@ -1126,8 +1127,62 @@ void LLVivoxVoiceClient::stateMachine()
}
break;
-
- //MARK: stateConnectorStart
+
+ //MARK: stateCaptureBufferPaused
+ case stateCaptureBufferPaused:
+ if (mCaptureBufferRecording)
+ {
+ setState(stateCaptureBufferRecStart);
+ // Update UI, should really be separated from the VoiceFont callback
+ notifyVoiceFontObservers();
+ }
+ else if (mCaptureBufferPlaying)
+ {
+ setState(stateCaptureBufferPlayStart);
+ notifyVoiceFontObservers();
+ }
+ else if (mCaptureBufferClear)
+ {
+ mCaptureBufferClear = false;
+ setState(stateNoChannel);
+ }
+ break;
+
+ //MARK: stateCaptureBufferRecStart
+ case stateCaptureBufferRecStart:
+ captureBufferRecordStartSendMessage();
+ setState(stateCaptureBufferRecording);
+ break;
+
+ //MARK: stateCaptureBufferRecording
+ case stateCaptureBufferRecording:
+ if (!mCaptureBufferRecording || mCaptureBufferPlaying || mCaptureBufferClear)
+ {
+ mCaptureBufferRecording = false;
+ captureBufferRecordStopSendMessage();
+ setState(stateCaptureBufferPaused);
+ notifyVoiceFontObservers();
+ }
+ break;
+
+ //MARK: stateCaptureBufferPlayStart
+ case stateCaptureBufferPlayStart:
+ captureBufferPlayStartSendMessage(mPreviewVoiceFontID);
+ setState(stateCaptureBufferPlaying);
+ break;
+
+ //MARK: stateCaptureBufferPlaying
+ case stateCaptureBufferPlaying:
+ if (!mCaptureBufferPlaying || mCaptureBufferRecording || mCaptureBufferClear)
+ {
+ mCaptureBufferPlaying = false;
+ captureBufferPlayStopSendMessage();
+ setState(stateCaptureBufferPaused);
+ notifyVoiceFontObservers();
+ }
+ break;
+
+ //MARK: stateConnectorStart
case stateConnectorStart:
if(!mVoiceEnabled)
{
@@ -1222,6 +1277,18 @@ 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);
+ refreshVoiceEffectLists(true);
+ }
+ else
+ {
+ setState(stateVoiceFontsReceived);
+ }
+
// request the current set of block rules (we'll need them when updating the friends list)
accountListBlockRulesSendMessage();
@@ -1253,12 +1320,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);
@@ -1306,6 +1382,11 @@ void LLVivoxVoiceClient::stateMachine()
mTuningExitState = stateNoChannel;
setState(stateMicTuningStart);
}
+ else if(mCaptureBufferRecording)
+ {
+ mTuningExitState = stateNoChannel;
+ setState(stateCaptureBufferRecStart);
+ }
else if(sessionNeedsRelog(mNextAudioSession))
{
requestRelog();
@@ -1316,6 +1397,7 @@ void LLVivoxVoiceClient::stateMachine()
sessionState *oldSession = mAudioSession;
mAudioSession = mNextAudioSession;
+ mAudioSessionChanged = true;
if(!mAudioSession->mReconnect)
{
mNextAudioSession = NULL;
@@ -1547,6 +1629,8 @@ void LLVivoxVoiceClient::stateMachine()
mAccountHandle.clear();
deleteAllSessions();
deleteAllBuddies();
+ deleteVoiceFonts();
+ deleteVoiceFontTemplates();
if(mVoiceEnabled && !mRelogRequested)
{
@@ -1627,15 +1711,15 @@ void LLVivoxVoiceClient::stateMachine()
}
- if(mAudioSession && mAudioSession->mParticipantsChanged)
+ if (mAudioSessionChanged)
{
- mAudioSession->mParticipantsChanged = false;
- mAudioSessionChanged = true;
+ mAudioSessionChanged = false;
+ notifyParticipantObservers();
+ notifyVoiceFontObservers();
}
-
- if(mAudioSessionChanged)
+ else if (mAudioSession && mAudioSession->mParticipantsChanged)
{
- mAudioSessionChanged = false;
+ mAudioSession->mParticipantsChanged = false;
notifyParticipantObservers();
}
}
@@ -1751,8 +1835,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 +1863,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 +1875,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 +1905,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 +1916,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 +1929,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 +3252,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.
@@ -3434,6 +3530,22 @@ void LLVivoxVoiceClient::accountLoginStateChangeEvent(
}
}
+void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType)
+{
+ if (mediaCompletionType == "AuxBufferAudioCapture")
+ {
+ mCaptureBufferRecording = false;
+ }
+ else if (mediaCompletionType == "AuxBufferAudioRender")
+ {
+ mCaptureBufferPlaying = false;
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Unknown MediaCompletionType: " << mediaCompletionType << LL_ENDL;
+ }
+}
+
void LLVivoxVoiceClient::mediaStreamUpdatedEvent(
std::string &sessionHandle,
std::string &sessionGroupHandle,
@@ -4134,8 +4246,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 +4742,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 +5762,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 +6192,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 +6356,499 @@ 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;
+}
+
+LLSD LLVivoxVoiceClient::getVoiceEffectProperties(const LLUUID& id)
+{
+ LLSD sd;
+
+ voice_font_map_t::iterator iter = mVoiceFontMap.find(id);
+ if (iter != mVoiceFontMap.end())
+ {
+ sd["template_only"] = false;
+ }
+ else
+ {
+ // Voice effect is not in the voice font map, see if there is a template
+ iter = mVoiceFontTemplateMap.find(id);
+ if (iter == mVoiceFontTemplateMap.end())
+ {
+ LL_WARNS("Voice") << "Voice effect " << id << "not found." << LL_ENDL;
+ return sd;
+ }
+ sd["template_only"] = true;
+ }
+
+ voiceFontEntry *font = iter->second;
+ sd["name"] = font->mName;
+ sd["expired"] = font->mHasExpired;
+ sd["expiry_date"] = font->mExpirationDate;
+ sd["is_new"] = font->mIsNew;
+
+ return sd;
+}
+
+LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) :
+ mID(id),
+ mFontIndex(0),
+ mHasExpired(false),
+ mFontType(VOICE_FONT_TYPE_NONE),
+ mFontStatus(VOICE_FONT_STATUS_NONE),
+ mIsNew(false)
+{
+}
+
+LLVivoxVoiceClient::voiceFontEntry::~voiceFontEntry()
+{
+}
+
+void LLVivoxVoiceClient::refreshVoiceEffectLists(bool clear_lists)
+{
+ if (clear_lists)
+ {
+ mVoiceFontsReceived = false;
+ deleteVoiceFonts();
+ deleteVoiceFontTemplates();
+ }
+
+ accountGetSessionFontsSendMessage();
+ accountGetTemplateFontsSendMessage();
+}
+
+const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectList() const
+{
+ return mVoiceFontList;
+}
+
+const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectTemplateList() const
+{
+ return mVoiceFontTemplateList;
+}
+
+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;
+
+ // Check whether we've seen this font before and create an entry for it if not.
+ voice_font_map_t::iterator iter = font_map.find(font_id);
+ bool new_font = (iter == font_map.end());
+ if (new_font)
+ {
+ font = new voiceFontEntry(font_id);
+ }
+ else
+ {
+ font = iter->second;
+ }
+
+ if (font)
+ {
+ font->mFontIndex = font_index;
+ // Use the description for the human readable name if available, as the
+ // "name" may 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;
+
+ // Only flag it as a new font if we have already seen the font list.
+ if (!template_font && mVoiceFontsReceived && new_font)
+ {
+ font->mIsNew = true;
+ mVoiceFontsNew = true;
+ }
+
+ 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 (new_font)
+ {
+ 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;
+}
+
+S32 LLVivoxVoiceClient::getVoiceFontTemplateIndex(const LLUUID& id) const
+{
+ S32 result = 0;
+ if (!id.isNull())
+ {
+ voice_font_map_t::const_iterator it = mVoiceFontTemplateMap.find(id);
+ if (it != mVoiceFontTemplateMap.end())
+ {
+ result = it->second->mFontIndex;
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Selected voice font template " << 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);
+ }
+ mVoiceFontsReceived = true;
+
+ notifyVoiceFontObservers(mVoiceFontsNew);
+ mVoiceFontsNew = false;
+}
+
+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(bool new_fonts)
+{
+ for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin();
+ it != mVoiceFontObservers.end();
+ )
+ {
+ LLVoiceEffectObserver* observer = *it;
+ observer->onVoiceEffectChanged(new_fonts);
+ // In case onVoiceEffectChanged() deleted an entry.
+ it = mVoiceFontObservers.upper_bound(observer);
+ }
+}
+
+void LLVivoxVoiceClient::recordPreviewBuffer(bool enable)
+{
+ if (enable)
+ {
+ mCaptureBufferRecording = true;
+ LL_DEBUGS("Voice") << "Starting recording" << LL_ENDL;
+ if(getState() >= stateNoChannel)
+ {
+ LL_DEBUGS("Voice") << "no channel" << LL_ENDL;
+ sessionTerminate();
+ }
+ }
+ else
+ {
+ mCaptureBufferRecording = false;
+ }
+}
+
+void LLVivoxVoiceClient::playPreviewBuffer(bool enable, const LLUUID& effect_id)
+{
+ if (enable && !isPreviewReady())
+ {
+ LL_DEBUGS("Voice") << "No preview buffer to play" << LL_ENDL;
+ return;
+ }
+
+ mCaptureBufferPlaying = enable;
+ if (mCaptureBufferPlaying)
+ {
+ mPreviewVoiceFontID = effect_id;
+ }
+}
+
+void LLVivoxVoiceClient::clearPreviewBuffer()
+{
+ mCaptureBufferClear = true;
+}
+
+bool LLVivoxVoiceClient::isPreviewRecording()
+{
+ return mCaptureBufferRecording;
+}
+
+bool LLVivoxVoiceClient::isPreviewReady()
+{
+ state preview_state = getState();
+ switch (preview_state)
+ {
+ case stateCaptureBufferPaused:
+ case stateCaptureBufferRecording:
+ case stateCaptureBufferPlaying:
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+}
+
+bool LLVivoxVoiceClient::isPreviewPlaying()
+{
+ return mCaptureBufferPlaying;
+}
+
+void LLVivoxVoiceClient::captureBufferRecordStartSendMessage()
+{ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Starting audio capture to buffer." << LL_ENDL;
+
+ // Start capture
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.StartBufferCapture.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ // Unmute the mic
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<Value>false</Value>"
+ << "</Request>\n\n\n";
+
+ // Dirty the PTT state so that it will get reset when we finishing previewing
+ mPTTDirty = true;
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::captureBufferRecordStopSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Stopping audio capture to buffer." << LL_ENDL;
+
+ // Mute the mic. PTT state was dirtied at recording start, so will be reset when finished previewing.
+ stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
+ << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
+ << "<Value>true</Value>"
+ << "</Request>\n\n\n";
+
+ // Stop capture
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::captureBufferPlayStartSendMessage(const LLUUID& voice_font_id)
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Starting audio buffer playback." << LL_ENDL;
+
+ S32 font_index = getVoiceFontTemplateIndex(voice_font_id);
+ LL_DEBUGS("Voice") << "With voice font: " << voice_font_id << " (" << font_index << ")" << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.PlayAudioBuffer.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "<TemplateFontID>" << font_index << "</TemplateFontID>"
+ << "<FontDelta />"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
+
+void LLVivoxVoiceClient::captureBufferPlayStopSendMessage()
+{
+ if(!mAccountHandle.empty())
+ {
+ std::ostringstream stream;
+
+ LL_DEBUGS("Voice") << "Stopping audio buffer playback." << LL_ENDL;
+
+ stream
+ << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
+ << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
+ << "</Request>"
+ << "\n\n\n";
+
+ writeString(stream.str());
+ }
+}
LLVivoxProtocolParser::LLVivoxProtocolParser()
{
@@ -6457,7 +7067,30 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
{
LLVivoxVoiceClient::getInstance()->deleteAllAutoAcceptRules();
}
-
+ else if (!stricmp("SessionFont", tag))
+ {
+ id = 0;
+ nameString.clear();
+ descriptionString.clear();
+ expirationDateString.clear();
+ hasExpired = false;
+ fontType = 0;
+ fontStatus = 0;
+ }
+ else if (!stricmp("TemplateFont", tag))
+ {
+ id = 0;
+ nameString.clear();
+ descriptionString.clear();
+ expirationDateString.clear();
+ hasExpired = false;
+ fontType = 0;
+ fontStatus = 0;
+ }
+ else if (!stricmp("MediaCompletionType", tag))
+ {
+ mediaCompletionType.clear();
+ }
}
}
responseDepth++;
@@ -6603,8 +7236,43 @@ 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);
+ }
+ else if (!stricmp("MediaCompletionType", tag))
+ {
+ mediaCompletionType = string;;
+ }
+
textBuffer.clear();
accumulateText= false;
@@ -6686,7 +7354,17 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
</Event>
*/
LLVivoxVoiceClient::getInstance()->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming);
- }
+ }
+ else if (!stricmp(eventTypeCstr, "MediaCompletionEvent"))
+ {
+ /*
+ <Event type="MediaCompletionEvent">
+ <SessionGroupHandle />
+ <MediaCompletionType>AuxBufferAudioCapture</MediaCompletionType>
+ </Event>
+ */
+ LLVivoxVoiceClient::getInstance()->mediaCompletionEvent(sessionGroupHandle, mediaCompletionType);
+ }
else if (!stricmp(eventTypeCstr, "TextStreamUpdatedEvent"))
{
/*
@@ -6747,6 +7425,9 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
}
else if (!stricmp(eventTypeCstr, "AuxAudioPropertiesEvent"))
{
+ // These are really spamming in tuning mode
+ squelchDebugOutput = true;
+
LLVivoxVoiceClient::getInstance()->auxAudioPropertiesEvent(energy);
}
else if (!stricmp(eventTypeCstr, "BuddyPresenceEvent"))
@@ -6861,6 +7542,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"))
{