From 009db32afecd7e95e6dd37cb8b9899829783a5d4 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Fri, 14 May 2010 13:11:18 +0100 Subject: EXT-7138 WIP added a refreshVoiceEffectLists() method to LLVoiceEffectInterface --- indra/newview/llvoicevivox.cpp | 74 +++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 34 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index a2ea21056d..aa2fa45b6d 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -337,10 +337,10 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mVoiceEnabled(false), mWriteInProgress(false), - mLipSyncEnabled(false) - - + mLipSyncEnabled(false), + mVoiceFontsReceived(false), + mVoiceFontsNew(false) { mSpeakerVolume = scale_speaker_volume(0); @@ -1220,13 +1220,12 @@ void LLVivoxVoiceClient::stateMachine() { // request the set of available voice fonts setState(stateVoiceFontsWait); - accountGetSessionFontsSendMessage(); + refreshVoiceEffectLists(true); } 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(); @@ -6317,7 +6316,8 @@ LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) : mFontIndex(0), mHasExpired(false), mFontType(VOICE_FONT_TYPE_NONE), - mFontStatus(VOICE_FONT_STATUS_NONE) + mFontStatus(VOICE_FONT_STATUS_NONE), + mIsNew(false) { } @@ -6325,6 +6325,19 @@ LLVivoxVoiceClient::voiceFontEntry::~voiceFontEntry() { } +void LLVivoxVoiceClient::refreshVoiceEffectLists(bool clear_lists) +{ + if (clear_lists) + { + mVoiceFontsReceived = false; + deleteVoiceFonts(); + deleteVoiceFontTemplates(); + } + + accountGetSessionFontsSendMessage(); + accountGetTemplateFontsSendMessage(); +} + void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, const std::string &name, const std::string &description, @@ -6337,7 +6350,7 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, // 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 + // If received name is not a UUID, fudge one by hashing the name and type. LLUUID font_id; if (LLUUID::validate(name)) { @@ -6353,38 +6366,36 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, 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. + // 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 duplicate = (iter != font_map.end()); - if (duplicate) + bool new_font = (iter == font_map.end()); + if (new_font) { - LL_DEBUGS("Voice") << "Voice font " << font_index << " duplicates " << iter->second->mFontIndex << "!" << LL_ENDL; - - if (!has_expired) - { - font = iter->second; - } + font = new voiceFontEntry(font_id); } else { - font = new voiceFontEntry(font_id); + font = iter->second; } if (font) { font->mFontIndex = font_index; // Use the description for the human readable name if available, as the - // "name" will probably be a UUID. + // "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; @@ -6398,7 +6409,7 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, LL_DEBUGS("Voice") << "Unknown voice font status: " << font_status << LL_ENDL; } - if (!duplicate) + 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)); @@ -6507,7 +6518,10 @@ void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const st { setState(stateVoiceFontsReceived); } - notifyVoiceFontObservers(); + mVoiceFontsReceived = true; + + notifyVoiceFontObservers(mVoiceFontsNew); + mVoiceFontsNew = false; } void LLVivoxVoiceClient::accountGetTemplateFontsResponse(int statusCode, const std::string &statusString) @@ -6525,14 +6539,14 @@ void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer) mVoiceFontObservers.erase(observer); } -void LLVivoxVoiceClient::notifyVoiceFontObservers() +void LLVivoxVoiceClient::notifyVoiceFontObservers(bool new_fonts) { for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin(); it != mVoiceFontObservers.end(); ) { LLVoiceEffectObserver* observer = *it; - observer->onVoiceEffectChanged(); + observer->onVoiceEffectChanged(new_fonts); // In case onVoiceEffectChanged() deleted an entry. it = mVoiceFontObservers.upper_bound(observer); } @@ -6755,10 +6769,6 @@ 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; @@ -6769,10 +6779,6 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) fontType = 0; fontStatus = 0; } - else if (!stricmp("TemplateFonts", tag)) - { - LLVivoxVoiceClient::getInstance()->deleteVoiceFontTemplates(); - } else if (!stricmp("TemplateFont", tag)) { id = 0; -- cgit v1.2.3 From 110995427fecaf59b4e7885893243a3bb07000db Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Tue, 18 May 2010 14:07:35 +0100 Subject: EXT-7138 WIP Moved implementation of LLVivoxVoiceClient::getVoiceEffectList() and LLVivoxVoiceClient::getVoiceEffectTemplateList() out of the header file --- indra/newview/llvoicevivox.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index aa2fa45b6d..2fba8e7b5f 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6338,6 +6338,16 @@ void LLVivoxVoiceClient::refreshVoiceEffectLists(bool clear_lists) 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, -- cgit v1.2.3 From 75f6e32f8836b008485ff65a17c2393696aa8fee Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Tue, 18 May 2010 14:12:54 +0100 Subject: EXT-7337 WIP Added capture buffer for previewing voice fonts to the voice client. --- indra/newview/llvoicevivox.cpp | 233 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 3 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 2fba8e7b5f..ee67879d3d 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -340,7 +340,10 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mLipSyncEnabled(false), mVoiceFontsReceived(false), - mVoiceFontsNew(false) + mVoiceFontsNew(false), + + mCaptureBufferRecording(false), + mCaptureBufferPlaying(false) { mSpeakerVolume = scale_speaker_volume(0); @@ -643,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); @@ -1119,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) { @@ -1320,6 +1382,11 @@ void LLVivoxVoiceClient::stateMachine() mTuningExitState = stateNoChannel; setState(stateMicTuningStart); } + else if(mCaptureBufferRecording) + { + mTuningExitState = stateNoChannel; + setState(stateCaptureBufferRecStart); + } else if(sessionNeedsRelog(mNextAudioSession)) { requestRelog(); @@ -6562,6 +6629,163 @@ void LLVivoxVoiceClient::notifyVoiceFontObservers(bool new_fonts) } } +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 + << "" + << "" << mAccountHandle << "" + << "" + << "\n\n\n"; + + // Unmute the mic + stream << "" + << "" << mConnectorHandle << "" + << "false" + << "\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 << "" + << "" << mConnectorHandle << "" + << "true" + << "\n\n\n"; + + // Stop capture + stream + << "" + << "" << mAccountHandle << "" + << "" + << "\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 = getVoiceFontIndex(voice_font_id); + LL_DEBUGS("Voice") << "With voice font: " << voice_font_id << " (" << font_index << ")" << LL_ENDL; + + stream + << "" + << "" << mAccountHandle << "" + << "" << font_index << "" + << "" + << "" + << "\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 + << "" + << "" << mAccountHandle << "" + << "" + << "\n\n\n"; + + writeString(stream.str()); + } +} + LLVivoxProtocolParser::LLVivoxProtocolParser() { parser = NULL; @@ -7119,6 +7343,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")) -- cgit v1.2.3 From be0662234565f772fc4c89e47400dc9df8277800 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Wed, 19 May 2010 16:25:52 +0100 Subject: EXT-7337 WIP Voice font previewing Added LLVoiceEffectInterface::getVoiceEffectProperties Added LLVivoxVoiceClient::getVoiceFontTemplateIndex --- indra/newview/llvoicevivox.cpp | 50 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index ee67879d3d..2df9152a17 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6378,6 +6378,36 @@ 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), @@ -6536,6 +6566,24 @@ S32 LLVivoxVoiceClient::getVoiceFontIndex(const LLUUID& id) const 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()) @@ -6753,7 +6801,7 @@ void LLVivoxVoiceClient::captureBufferPlayStartSendMessage(const LLUUID& voice_f LL_DEBUGS("Voice") << "Starting audio buffer playback." << LL_ENDL; - S32 font_index = getVoiceFontIndex(voice_font_id); + S32 font_index = getVoiceFontTemplateIndex(voice_font_id); LL_DEBUGS("Voice") << "With voice font: " << voice_font_id << " (" << font_index << ")" << LL_ENDL; stream -- cgit v1.2.3 From 4c6d743665ae39a6402ee7b86f43043cb4c5806d Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Wed, 19 May 2010 21:13:19 +0100 Subject: EXT-7337 WIP Voice font previewing Handle mediaCompletionEvents in the voice client to update UI when preview playback ends. --- indra/newview/llvoicevivox.cpp | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 2df9152a17..7daf865151 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -3530,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, @@ -7071,6 +7087,10 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) fontType = 0; fontStatus = 0; } + else if (!stricmp("MediaCompletionType", tag)) + { + mediaCompletionType.clear(); + } } } responseDepth++; @@ -7248,7 +7268,11 @@ void LLVivoxProtocolParser::EndTag(const char *tag) { fontStatus = strtol(string.c_str(), NULL, 10); } - + else if (!stricmp("MediaCompletionType", tag)) + { + mediaCompletionType = string;; + } + textBuffer.clear(); accumulateText= false; @@ -7330,7 +7354,17 @@ void LLVivoxProtocolParser::processResponse(std::string tag) */ LLVivoxVoiceClient::getInstance()->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming); - } + } + else if (!stricmp(eventTypeCstr, "MediaCompletionEvent")) + { + /* + + + AuxBufferAudioCapture + + */ + LLVivoxVoiceClient::getInstance()->mediaCompletionEvent(sessionGroupHandle, mediaCompletionType); + } else if (!stricmp(eventTypeCstr, "TextStreamUpdatedEvent")) { /* -- cgit v1.2.3 From 5cf632aacbae683676c341a7f1470108cdf65b59 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Sat, 22 May 2010 17:58:45 +0100 Subject: EXT-7138 WIP Voice Morphing - Go into stateCaptureBufferPaused as soon as the Voice Effects preview is opened. Disconnecting from voice on hitting record was taking too long and causing the start of the voice recording to be cut off. --- indra/newview/llvoicevivox.cpp | 86 +++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 47 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 7daf865151..a64c05a3c6 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -342,7 +342,9 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mVoiceFontsReceived(false), mVoiceFontsNew(false), + mCaptureBufferMode(false), mCaptureBufferRecording(false), + mCaptureBufferRecorded(false), mCaptureBufferPlaying(false) { mSpeakerVolume = scale_speaker_volume(0); @@ -1130,7 +1132,12 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateCaptureBufferPaused case stateCaptureBufferPaused: - if (mCaptureBufferRecording) + if (!mCaptureBufferMode) + { + mCaptureBufferRecorded = false; + setState(stateNoChannel); + } + else if (mCaptureBufferRecording) { setState(stateCaptureBufferRecStart); // Update UI, should really be separated from the VoiceFont callback @@ -1141,22 +1148,18 @@ void LLVivoxVoiceClient::stateMachine() setState(stateCaptureBufferPlayStart); notifyVoiceFontObservers(); } - else if (mCaptureBufferClear) - { - mCaptureBufferClear = false; - setState(stateNoChannel); - } break; //MARK: stateCaptureBufferRecStart case stateCaptureBufferRecStart: captureBufferRecordStartSendMessage(); + mCaptureBufferRecorded = true; setState(stateCaptureBufferRecording); break; //MARK: stateCaptureBufferRecording case stateCaptureBufferRecording: - if (!mCaptureBufferRecording || mCaptureBufferPlaying || mCaptureBufferClear) + if (!mCaptureBufferMode || !mCaptureBufferRecording || mCaptureBufferPlaying) { mCaptureBufferRecording = false; captureBufferRecordStopSendMessage(); @@ -1173,7 +1176,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateCaptureBufferPlaying case stateCaptureBufferPlaying: - if (!mCaptureBufferPlaying || mCaptureBufferRecording || mCaptureBufferClear) + if (!mCaptureBufferMode || !mCaptureBufferPlaying || mCaptureBufferRecording) { mCaptureBufferPlaying = false; captureBufferPlayStopSendMessage(); @@ -1382,10 +1385,9 @@ void LLVivoxVoiceClient::stateMachine() mTuningExitState = stateNoChannel; setState(stateMicTuningStart); } - else if(mCaptureBufferRecording) + else if(mCaptureBufferMode) { - mTuningExitState = stateNoChannel; - setState(stateCaptureBufferRecStart); + setState(stateCaptureBufferPaused); } else if(sessionNeedsRelog(mNextAudioSession)) { @@ -6693,42 +6695,43 @@ void LLVivoxVoiceClient::notifyVoiceFontObservers(bool new_fonts) } } -void LLVivoxVoiceClient::recordPreviewBuffer(bool enable) +void LLVivoxVoiceClient::enablePreviewBuffer(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 + mCaptureBufferMode = enable; + if(mCaptureBufferMode && getState() >= stateNoChannel) { - mCaptureBufferRecording = false; + LL_DEBUGS("Voice") << "no channel" << LL_ENDL; + sessionTerminate(); } } -void LLVivoxVoiceClient::playPreviewBuffer(bool enable, const LLUUID& effect_id) +void LLVivoxVoiceClient::recordPreviewBuffer(bool record) { - if (enable && !isPreviewReady()) + if (record && !mCaptureBufferMode) { - LL_DEBUGS("Voice") << "No preview buffer to play" << LL_ENDL; + LL_DEBUGS("Voice") << "Cannot start recording, not in preview mode." << LL_ENDL; return; } - mCaptureBufferPlaying = enable; - if (mCaptureBufferPlaying) - { - mPreviewVoiceFontID = effect_id; - } + mCaptureBufferRecording = record; } -void LLVivoxVoiceClient::clearPreviewBuffer() +void LLVivoxVoiceClient::playPreviewBuffer(bool play, const LLUUID& effect_id) { - mCaptureBufferClear = true; + if (play) + { + if (mCaptureBufferMode && mCaptureBufferRecorded) + { + mPreviewVoiceFontID = effect_id; + } + else + { + LL_DEBUGS("Voice") << "No preview buffer to play." << LL_ENDL; + return; + } + } + + mCaptureBufferPlaying = play; } bool LLVivoxVoiceClient::isPreviewRecording() @@ -6738,18 +6741,8 @@ bool LLVivoxVoiceClient::isPreviewRecording() bool LLVivoxVoiceClient::isPreviewReady() { - state preview_state = getState(); - switch (preview_state) - { - case stateCaptureBufferPaused: - case stateCaptureBufferRecording: - case stateCaptureBufferPlaying: - return true; - break; - default: - return false; - break; - } + return mCaptureBufferRecorded; + } bool LLVivoxVoiceClient::isPreviewPlaying() @@ -6767,7 +6760,6 @@ void LLVivoxVoiceClient::captureBufferRecordStartSendMessage() // Start capture stream << "" - << "" << mAccountHandle << "" << "" << "\n\n\n"; -- cgit v1.2.3 From 32826f31ebfe19f57a1d8cc7c2f3e81df9b5de74 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Sat, 22 May 2010 18:09:56 +0100 Subject: EXT-7337 WIP Voice Morphing - Limit maximum recording sample to 15 seconds. --- indra/newview/llvoicevivox.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index a64c05a3c6..f1c8ce21d2 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -96,6 +96,9 @@ 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; +// Maximum length of capture buffer recordings +const F32 CAPTURE_BUFFER_MAX_TIME = 15.f; + static int scale_mic_volume(float volume) { @@ -1154,12 +1157,15 @@ void LLVivoxVoiceClient::stateMachine() case stateCaptureBufferRecStart: captureBufferRecordStartSendMessage(); mCaptureBufferRecorded = true; + mCaptureTimer.start(); + mCaptureTimer.setTimerExpirySec(CAPTURE_BUFFER_MAX_TIME); setState(stateCaptureBufferRecording); break; //MARK: stateCaptureBufferRecording case stateCaptureBufferRecording: - if (!mCaptureBufferMode || !mCaptureBufferRecording || mCaptureBufferPlaying) + if (!mCaptureBufferMode || !mCaptureBufferRecording || + mCaptureBufferPlaying || mCaptureTimer.hasExpired()) { mCaptureBufferRecording = false; captureBufferRecordStopSendMessage(); -- cgit v1.2.3 From 1ebbe196910110eb51497f272abde277f8f0f69a Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Sun, 23 May 2010 02:22:48 +0100 Subject: EXT-7337 WIP Voice morph previewing Separate Play and Stop callbacks, to allow single click previews in the effect list. --- indra/newview/llvoicevivox.cpp | 118 +++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 35 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index f1c8ce21d2..ba68795870 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -348,7 +348,8 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mCaptureBufferMode(false), mCaptureBufferRecording(false), mCaptureBufferRecorded(false), - mCaptureBufferPlaying(false) + mCaptureBufferPlaying(false), + mPlayRequestCount(0) { mSpeakerVolume = scale_speaker_volume(0); @@ -1137,28 +1138,39 @@ void LLVivoxVoiceClient::stateMachine() case stateCaptureBufferPaused: if (!mCaptureBufferMode) { + // Leaving capture mode. + + mCaptureBufferRecording = false; mCaptureBufferRecorded = false; + mCaptureBufferPlaying = false; + + // Return to stateNoChannel to trigger reconnection to a channel. setState(stateNoChannel); } else if (mCaptureBufferRecording) { setState(stateCaptureBufferRecStart); - // Update UI, should really be separated from the VoiceFont callback - notifyVoiceFontObservers(); } else if (mCaptureBufferPlaying) { setState(stateCaptureBufferPlayStart); - notifyVoiceFontObservers(); } break; //MARK: stateCaptureBufferRecStart case stateCaptureBufferRecStart: captureBufferRecordStartSendMessage(); + + // Flag that something is recorded to allow playback. mCaptureBufferRecorded = true; + + // Start the timer, recording will be stopped when it expires. mCaptureTimer.start(); mCaptureTimer.setTimerExpirySec(CAPTURE_BUFFER_MAX_TIME); + + // Update UI, should really use a separate callback. + notifyVoiceFontObservers(false); + setState(stateCaptureBufferRecording); break; @@ -1167,27 +1179,47 @@ void LLVivoxVoiceClient::stateMachine() if (!mCaptureBufferMode || !mCaptureBufferRecording || mCaptureBufferPlaying || mCaptureTimer.hasExpired()) { - mCaptureBufferRecording = false; + // Stop recording captureBufferRecordStopSendMessage(); + mCaptureBufferRecording = false; + + // Update UI, should really use a separate callback. + notifyVoiceFontObservers(false); + setState(stateCaptureBufferPaused); - notifyVoiceFontObservers(); } break; //MARK: stateCaptureBufferPlayStart case stateCaptureBufferPlayStart: - captureBufferPlayStartSendMessage(mPreviewVoiceFontID); + captureBufferPlayStartSendMessage(mPreviewVoiceFont); + + // Store the voice font being previewed, so that we know to restart if it changes. + mPreviewVoiceFontLast = mPreviewVoiceFont; + + // Update UI, should really use a separate callback. + notifyVoiceFontObservers(false); + setState(stateCaptureBufferPlaying); break; //MARK: stateCaptureBufferPlaying case stateCaptureBufferPlaying: - if (!mCaptureBufferMode || !mCaptureBufferPlaying || mCaptureBufferRecording) + if (mCaptureBufferPlaying && mPreviewVoiceFont != mPreviewVoiceFontLast) { - mCaptureBufferPlaying = false; + // If the preview voice font changes, restart playing with the new font. + setState(stateCaptureBufferPlayStart); + } + else if (!mCaptureBufferMode || !mCaptureBufferPlaying || mCaptureBufferRecording) + { + // Stop playing. captureBufferPlayStopSendMessage(); + mCaptureBufferPlaying = false; + + // Update UI, should really use a separate callback. + notifyVoiceFontObservers(false); + setState(stateCaptureBufferPaused); - notifyVoiceFontObservers(); } break; @@ -1723,7 +1755,7 @@ void LLVivoxVoiceClient::stateMachine() { mAudioSessionChanged = false; notifyParticipantObservers(); - notifyVoiceFontObservers(); + notifyVoiceFontObservers(false); } else if (mAudioSession && mAudioSession->mParticipantsChanged) { @@ -3546,7 +3578,11 @@ void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, s } else if (mediaCompletionType == "AuxBufferAudioRender") { - mCaptureBufferPlaying = false; + // Ignore all but the last stop event + if (--mPlayRequestCount <= 0) + { + mCaptureBufferPlaying = false; + } } else { @@ -6392,7 +6428,7 @@ bool LLVivoxVoiceClient::setVoiceEffect(const LLUUID& id) gSavedPerAccountSettings.setString("VoiceEffectDefault", id.asString()); sessionSetVoiceFontSendMessage(mAudioSession); - notifyVoiceFontObservers(); + notifyVoiceFontObservers(false); return true; } @@ -6669,14 +6705,13 @@ void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const st } mVoiceFontsReceived = true; - notifyVoiceFontObservers(mVoiceFontsNew); - mVoiceFontsNew = false; + notifyVoiceFontObservers(true); } void LLVivoxVoiceClient::accountGetTemplateFontsResponse(int statusCode, const std::string &statusString) { // Voice font list entries were updated via addVoiceFont() during parsing. - notifyVoiceFontObservers(); + notifyVoiceFontObservers(true); } void LLVivoxVoiceClient::addObserver(LLVoiceEffectObserver* observer) { @@ -6711,49 +6746,58 @@ void LLVivoxVoiceClient::enablePreviewBuffer(bool enable) } } -void LLVivoxVoiceClient::recordPreviewBuffer(bool record) +void LLVivoxVoiceClient::recordPreviewBuffer() { - if (record && !mCaptureBufferMode) + if (!mCaptureBufferMode) { - LL_DEBUGS("Voice") << "Cannot start recording, not in preview mode." << LL_ENDL; + LL_DEBUGS("Voice") << "Not in voice effect preview mode, cannot start recording." << LL_ENDL; + mCaptureBufferRecording = false; return; } - mCaptureBufferRecording = record; + mCaptureBufferRecording = true; } -void LLVivoxVoiceClient::playPreviewBuffer(bool play, const LLUUID& effect_id) +void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id) { - if (play) + if (!mCaptureBufferMode) { - if (mCaptureBufferMode && mCaptureBufferRecorded) - { - mPreviewVoiceFontID = effect_id; - } - else - { - LL_DEBUGS("Voice") << "No preview buffer to play." << LL_ENDL; - return; - } + LL_DEBUGS("Voice") << "Not in voice effect preview mode, no buffer to play." << LL_ENDL; + mCaptureBufferRecording = false; + return; + } + + if (!mCaptureBufferRecorded) + { + // Can't play until we have something recorded! + mCaptureBufferPlaying = false; + return; } - mCaptureBufferPlaying = play; + mPreviewVoiceFont = effect_id; + mCaptureBufferPlaying = true; +} + +void LLVivoxVoiceClient::stopPreviewBuffer() +{ + mCaptureBufferRecording = false; + mCaptureBufferPlaying = false; } bool LLVivoxVoiceClient::isPreviewRecording() { - return mCaptureBufferRecording; + return (mCaptureBufferMode && mCaptureBufferRecording); } bool LLVivoxVoiceClient::isPreviewReady() { - return mCaptureBufferRecorded; + return (mCaptureBufferMode && mCaptureBufferRecorded); } bool LLVivoxVoiceClient::isPreviewPlaying() { - return mCaptureBufferPlaying; + return (mCaptureBufferMode && mCaptureBufferPlaying); } void LLVivoxVoiceClient::captureBufferRecordStartSendMessage() @@ -6811,6 +6855,10 @@ void LLVivoxVoiceClient::captureBufferPlayStartSendMessage(const LLUUID& voice_f { if(!mAccountHandle.empty()) { + // Track how may play requests are sent, so we know how many stop events to + // expect before play actually stops. + ++mPlayRequestCount; + std::ostringstream stream; LL_DEBUGS("Voice") << "Starting audio buffer playback." << LL_ENDL; -- cgit v1.2.3 From 1cb14cd52bdd7b795f081043fb4444e0a196f82b Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Sun, 23 May 2010 14:26:24 +0100 Subject: EXT-7337 WIP Removed now redundant isPreviewReady() method. --- indra/newview/llvoicevivox.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index ba68795870..e00b94b421 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6789,12 +6789,6 @@ bool LLVivoxVoiceClient::isPreviewRecording() return (mCaptureBufferMode && mCaptureBufferRecording); } -bool LLVivoxVoiceClient::isPreviewReady() -{ - return (mCaptureBufferMode && mCaptureBufferRecorded); - -} - bool LLVivoxVoiceClient::isPreviewPlaying() { return (mCaptureBufferMode && mCaptureBufferPlaying); -- cgit v1.2.3 From 08e610adfa8124fa7b990f952ad3053b955b62d3 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Sun, 23 May 2010 19:44:30 +0100 Subject: EXT-7335 WIP Parse Vivox voice font expiry timestamps into ISO 8601 standard dates. --- indra/newview/llvoicevivox.cpp | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e00b94b421..304321b361 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6508,7 +6508,7 @@ const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectTemplateList() cons void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, const std::string &name, const std::string &description, - const std::string &expiration_date, + const LLDate &expiration_date, const bool has_expired, const S32 font_type, const S32 font_status, @@ -7112,7 +7112,7 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) id = 0; nameString.clear(); descriptionString.clear(); - expirationDateString.clear(); + expirationDate = LLDate(); hasExpired = false; fontType = 0; fontStatus = 0; @@ -7122,7 +7122,7 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) id = 0; nameString.clear(); descriptionString.clear(); - expirationDateString.clear(); + expirationDate = LLDate(); hasExpired = false; fontType = 0; fontStatus = 0; @@ -7278,11 +7278,11 @@ void LLVivoxProtocolParser::EndTag(const char *tag) subscriptionType = string; else if (!stricmp("SessionFont", tag)) { - LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDateString, hasExpired, fontType, fontStatus, false); + LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, hasExpired, fontType, fontStatus, false); } else if (!stricmp("TemplateFont", tag)) { - LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDateString, hasExpired, fontType, fontStatus, true); + LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, hasExpired, fontType, fontStatus, true); } else if (!stricmp("ID", tag)) { @@ -7294,7 +7294,7 @@ void LLVivoxProtocolParser::EndTag(const char *tag) } else if (!stricmp("ExpirationDate", tag)) { - expirationDateString = string; + expirationDate = vivoxTimeStampToLLDate(string); } else if (!stricmp("Expired", tag)) { @@ -7341,6 +7341,34 @@ void LLVivoxProtocolParser::CharData(const char *buffer, int length) // -------------------------------------------------------------------------------- +LLDate LLVivoxProtocolParser::vivoxTimeStampToLLDate(const std::string& vivox_ts) +{ + // First check to see if it actually already is a proper ISO8601 date, + // in case the format miraculously changes in future ;) + LLDate ts(vivox_ts); + if (ts.notNull()) + { + return ts; + } + + std::string time_stamp = vivox_ts; + + // Vivox's format is missing a T from being standard ISO 8601, + // so add it. It is the only space in their result. + LLStringUtil::replaceChar(time_stamp, ' ', 'T'); + + //also need to remove the hours away from GMT to be compatible + //with LLDate as well as the fractions of seconds + time_stamp = time_stamp.substr(0, time_stamp.length() - 5); + + //it also needs a 'Z' at the end + time_stamp += "Z"; + + return LLDate(time_stamp); +} + +// -------------------------------------------------------------------------------- + void LLVivoxProtocolParser::processResponse(std::string tag) { LL_DEBUGS("VivoxProtocolParser") << tag << LL_ENDL; -- cgit v1.2.3 From 15c3b2c6309fa4b45376f3d62e33bfcd3ccdbfc7 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Mon, 24 May 2010 02:27:07 +0100 Subject: EXT-7335 WIP Added notification of expiring voice effects --- indra/newview/llvoicevivox.cpp | 187 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 171 insertions(+), 16 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 304321b361..d786b4d928 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -60,6 +60,7 @@ #include "llviewerparcelmgr.h" //#include "llfirstuse.h" #include "llspeakers.h" +#include "lltrans.h" #include "llviewerwindow.h" #include "llviewercamera.h" @@ -96,6 +97,9 @@ 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; +// How often to check for expired voice fonts +const F32 VOICE_FONT_EXPIRY_INTERVAL = 1.f; + // Maximum length of capture buffer recordings const F32 CAPTURE_BUFFER_MAX_TIME = 15.f; @@ -781,7 +785,7 @@ void LLVivoxVoiceClient::stateMachine() closeSocket(); deleteAllSessions(); deleteAllBuddies(); - deleteVoiceFonts(); + deleteAllVoiceFonts(); deleteVoiceFontTemplates(); mConnectorHandle.clear(); @@ -1372,6 +1376,10 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateVoiceFontsReceived case stateVoiceFontsReceived: // Voice font list received + // Set up the timer to check for expiring voice fonts + mVoiceFontExpiryTimer.start(); + mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL); + #if USE_SESSION_GROUPS // create the main session group setState(stateCreatingSessionGroup); @@ -1600,6 +1608,13 @@ void LLVivoxVoiceClient::stateMachine() enforceTether(); } + // Do notifications for expiring Voice Fonts. + if (mVoiceFontExpiryTimer.hasExpired()) + { + expireVoiceFonts(); + mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL); + } + // Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often // -- the user can only click so fast) or every 10hz, whichever is sooner. // Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged. @@ -1669,7 +1684,7 @@ void LLVivoxVoiceClient::stateMachine() mAccountHandle.clear(); deleteAllSessions(); deleteAllBuddies(); - deleteVoiceFonts(); + deleteAllVoiceFonts(); deleteVoiceFontTemplates(); if(mVoiceEnabled && !mRelogRequested) @@ -6461,7 +6476,6 @@ LLSD LLVivoxVoiceClient::getVoiceEffectProperties(const LLUUID& id) voiceFontEntry *font = iter->second; sd["name"] = font->mName; - sd["expired"] = font->mHasExpired; sd["expiry_date"] = font->mExpirationDate; sd["is_new"] = font->mIsNew; @@ -6471,7 +6485,6 @@ LLSD LLVivoxVoiceClient::getVoiceEffectProperties(const LLUUID& id) LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) : mID(id), mFontIndex(0), - mHasExpired(false), mFontType(VOICE_FONT_TYPE_NONE), mFontStatus(VOICE_FONT_STATUS_NONE), mIsNew(false) @@ -6487,7 +6500,7 @@ void LLVivoxVoiceClient::refreshVoiceEffectLists(bool clear_lists) if (clear_lists) { mVoiceFontsReceived = false; - deleteVoiceFonts(); + deleteAllVoiceFonts(); deleteVoiceFontTemplates(); } @@ -6533,12 +6546,23 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, 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. + // Check whether we've seen this font before. voice_font_map_t::iterator iter = font_map.find(font_id); bool new_font = (iter == font_map.end()); + + // If it is a new (unexpired) font create a new entry, otherwise update the existing one. if (new_font) { - font = new voiceFontEntry(font_id); + if (!has_expired) + { + font = new voiceFontEntry(font_id); + } + else + { + LL_DEBUGS("Voice") << (template_font?"Template: ":"") << font_id + << " (" << font_index << ") : " << name << " has expired." << LL_ENDL; + } + } else { @@ -6547,15 +6571,47 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, if (font) { + // Remove fonts that have expired since we last saw them. + if (has_expired) + { + LL_DEBUGS("Voice") << (template_font?"Template: ":"") << font_id + << " (" << font_index << ") : " << name << " has expired, removing." + << LL_ENDL; + + deleteVoiceFont(font_id); + return; + } + 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; + F64 expiry_time = 0.f; + + // Set the expiry timer to trigger a notification when the voice font can no longer be used. + font->mExpiryTimer.start(); + expiry_time = expiration_date.secondsSinceEpoch() - LLTimer::getTotalSeconds(); + font->mExpiryTimer.setTimerExpirySec(expiry_time); + + // Set the warning timer to some interval before actual expiry. + F64 warning_time = (F64)gSavedSettings.getF32("VoiceEffectExpiryWarningTime"); + if (warning_time > 0.f) + { + font->mExpiryWarningTimer.start(); + expiry_time = (expiration_date.secondsSinceEpoch() - warning_time) + - LLTimer::getTotalSeconds(); + font->mExpiryWarningTimer.setTimerExpirySec(expiry_time); + } + else + { + // Disable the warning timer. + font->mExpiryWarningTimer.stop(); + } + // Only flag it as a new font if we have already seen the font list. if (!template_font && mVoiceFontsReceived && new_font) { @@ -6563,9 +6619,16 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, mVoiceFontsNew = true; } + 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)); + } + + // Debugging stuff + LL_DEBUGS("Voice") << (template_font?"Template: ":"") << font_id - << " (" << font_index << ") : " << name << (has_expired?" (Expired)":"") - << LL_ENDL; + << " (" << font_index << ") : " << name << LL_ENDL; if (font_type < VOICE_FONT_TYPE_NONE || font_type >= VOICE_FONT_TYPE_UNKNOWN) { @@ -6575,16 +6638,108 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, { LL_DEBUGS("Voice") << "Unknown voice font status: " << font_status << LL_ENDL; } + } +} - if (new_font) +void LLVivoxVoiceClient::expireVoiceFonts() +{ + // *TODO: If we are selling voice fonts in packs, there are probably + // going to be a number of fonts with the same expiration time, so would + // be more efficient to just keep a list of expiration times rather + // than checking each font individually. + + bool have_expired = false; + bool will_expire = false; + bool expired_in_use = false; + + LLUUID current_effect = LLVoiceClient::instance().getVoiceEffectDefault(); + + voice_font_map_t::iterator iter; + for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter) + { + voiceFontEntry* voice_font = iter->second; + LLTimer& expiry_timer = voice_font->mExpiryTimer; + LLTimer& warning_timer = voice_font->mExpiryWarningTimer; + + // Check for expired voice fonts + if (expiry_timer.getStarted() && expiry_timer.hasExpired()) { - 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)); + // Check whether it is the active voice font + if (voice_font->mID == current_effect) + { + // Reset to no voice effect. + setVoiceEffect(LLUUID::null); + expired_in_use = true; + } + deleteVoiceFont(voice_font->mID); + have_expired = true; + } + + // Check for voice fonts that will expire in less that the warning time + if (warning_timer.getStarted() && warning_timer.hasExpired()) + { + will_expire = true; + warning_timer.stop(); + } + } + + LLSD args; + args["URL"] = LLTrans::getString("voice_morphing_url"); + + // Give a notification if any voice fonts have expired. + if (have_expired) + { + if (expired_in_use) + { + LLNotificationsUtil::add("VoiceEffectsExpiredInUse", args); + } + else + { + LLNotificationsUtil::add("VoiceEffectsExpired", args); + } + + // Refresh voice font lists in the UI. + notifyVoiceFontObservers(true); + } + + // Give a warning notification if any voice fonts are due to expire. + if (will_expire) + { + S32 seconds = gSavedSettings.getF32("VoiceEffectExpiryWarningTime"); + args["INTERVAL"] = llformat("%d", (seconds / SEC_PER_DAY)); + + LLNotificationsUtil::add("VoiceEffectsWillExpire", args); + } +} + +void LLVivoxVoiceClient::deleteVoiceFont(const LLUUID& id) +{ + // Remove the entry from the voice font list. + voice_effect_list_t::iterator list_iter = mVoiceFontList.begin(); + while (list_iter != mVoiceFontList.end()) + { + if (list_iter->second == id) + { + mVoiceFontList.erase(list_iter++); + } + else + { + ++list_iter; } } + + // Find the entry in the voice font map and erase its data. + voice_font_map_t::iterator map_iter = mVoiceFontMap.find(id); + if (map_iter != mVoiceFontMap.end()) + { + delete map_iter->second; + } + + // Remove the entry from the voice font map. + mVoiceFontMap.erase(map_iter); } -void LLVivoxVoiceClient::deleteVoiceFonts() +void LLVivoxVoiceClient::deleteAllVoiceFonts() { mVoiceFontList.clear(); @@ -6723,14 +6878,14 @@ void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer) mVoiceFontObservers.erase(observer); } -void LLVivoxVoiceClient::notifyVoiceFontObservers(bool new_fonts) +void LLVivoxVoiceClient::notifyVoiceFontObservers(bool lists_changed) { for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin(); it != mVoiceFontObservers.end(); ) { LLVoiceEffectObserver* observer = *it; - observer->onVoiceEffectChanged(new_fonts); + observer->onVoiceEffectChanged(lists_changed); // In case onVoiceEffectChanged() deleted an entry. it = mVoiceFontObservers.upper_bound(observer); } -- cgit v1.2.3 From 40e240fe61fe8ff989ac906969946d22a186bcf2 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Mon, 24 May 2010 03:00:29 +0100 Subject: EXT-7138 WIP Renamed VoiceEffectEnabled debug setting to VoiceMorphingEnabled. Hide Me->My Voice menu item when VoiceMorphing is disabled. Removed temporary VoiceFontsAvailable debug setting. --- indra/newview/llvoicevivox.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index d786b4d928..240d7ff164 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1322,8 +1322,7 @@ 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")) + if (LLVoiceClient::instance().getVoiceEffectEnabled()) { // request the set of available voice fonts setState(stateVoiceFontsWait); -- cgit v1.2.3 From 55c935ea764bc349fa5a329bf190cc6d00f343ca Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Mon, 24 May 2010 10:55:41 +0100 Subject: EXT-7335 WIP Changed VoiceEffectExpiryWarningTime from F32 to S32 --- indra/newview/llvoicevivox.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 240d7ff164..c8402af5d1 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6597,11 +6597,11 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, font->mExpiryTimer.setTimerExpirySec(expiry_time); // Set the warning timer to some interval before actual expiry. - F64 warning_time = (F64)gSavedSettings.getF32("VoiceEffectExpiryWarningTime"); - if (warning_time > 0.f) + S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime"); + if (warning_time > 0) { font->mExpiryWarningTimer.start(); - expiry_time = (expiration_date.secondsSinceEpoch() - warning_time) + expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time) - LLTimer::getTotalSeconds(); font->mExpiryWarningTimer.setTimerExpirySec(expiry_time); } @@ -6704,8 +6704,8 @@ void LLVivoxVoiceClient::expireVoiceFonts() // Give a warning notification if any voice fonts are due to expire. if (will_expire) { - S32 seconds = gSavedSettings.getF32("VoiceEffectExpiryWarningTime"); - args["INTERVAL"] = llformat("%d", (seconds / SEC_PER_DAY)); + S32 seconds = gSavedSettings.getS32("VoiceEffectExpiryWarningTime"); + args["INTERVAL"] = llformat("%d", seconds / SEC_PER_DAY); LLNotificationsUtil::add("VoiceEffectsWillExpire", args); } -- cgit v1.2.3 From 0fc44d319fbc0e5865e0ca76b51b2f436b72ad87 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Mon, 24 May 2010 15:11:46 +0100 Subject: EXT-7335 WIP Clean up warnings when parsing Vivox timestamps. Tidied up initialization of voice font expiry timers. --- indra/newview/llvoicevivox.cpp | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index c8402af5d1..070e4f0d2d 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6488,6 +6488,8 @@ LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) : mFontStatus(VOICE_FONT_STATUS_NONE), mIsNew(false) { + mExpiryTimer.stop(); + mExpiryWarningTimer.stop(); } LLVivoxVoiceClient::voiceFontEntry::~voiceFontEntry() @@ -6589,21 +6591,17 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, font->mFontType = font_type; font->mFontStatus = font_status; - F64 expiry_time = 0.f; - // Set the expiry timer to trigger a notification when the voice font can no longer be used. font->mExpiryTimer.start(); - expiry_time = expiration_date.secondsSinceEpoch() - LLTimer::getTotalSeconds(); - font->mExpiryTimer.setTimerExpirySec(expiry_time); + font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch()); // Set the warning timer to some interval before actual expiry. S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime"); - if (warning_time > 0) + if (warning_time != 0) { font->mExpiryWarningTimer.start(); - expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time) - - LLTimer::getTotalSeconds(); - font->mExpiryWarningTimer.setTimerExpirySec(expiry_time); + F64 expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time); + font->mExpiryWarningTimer.setExpiryAt(expiry_time); } else { @@ -6657,8 +6655,8 @@ void LLVivoxVoiceClient::expireVoiceFonts() for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter) { voiceFontEntry* voice_font = iter->second; - LLTimer& expiry_timer = voice_font->mExpiryTimer; - LLTimer& warning_timer = voice_font->mExpiryWarningTimer; + LLFrameTimer& expiry_timer = voice_font->mExpiryTimer; + LLFrameTimer& warning_timer = voice_font->mExpiryWarningTimer; // Check for expired voice fonts if (expiry_timer.getStarted() && expiry_timer.hasExpired()) @@ -7497,10 +7495,11 @@ void LLVivoxProtocolParser::CharData(const char *buffer, int length) LLDate LLVivoxProtocolParser::vivoxTimeStampToLLDate(const std::string& vivox_ts) { - // First check to see if it actually already is a proper ISO8601 date, + LLDate ts; + + // First check to see if it actually already is a parseable ISO8601 date, // in case the format miraculously changes in future ;) - LLDate ts(vivox_ts); - if (ts.notNull()) + if (ts.fromString(vivox_ts)) { return ts; } @@ -7511,14 +7510,22 @@ LLDate LLVivoxProtocolParser::vivoxTimeStampToLLDate(const std::string& vivox_ts // so add it. It is the only space in their result. LLStringUtil::replaceChar(time_stamp, ' ', 'T'); - //also need to remove the hours away from GMT to be compatible - //with LLDate as well as the fractions of seconds + // Also need to remove the hours away from GMT to be compatible + // with LLDate, as well as the fractions of seconds. time_stamp = time_stamp.substr(0, time_stamp.length() - 5); - //it also needs a 'Z' at the end + // It also needs a 'Z' at the end time_stamp += "Z"; - return LLDate(time_stamp); + ts.fromString(time_stamp); + if(!ts.fromString(time_stamp)) + { + LL_WARNS_ONCE("Voice") << "Failed to parse Vivox timestamp: " << vivox_ts + << " to ISO 8601 date: " << time_stamp << LL_ENDL; + return LLDate(); + } + + return ts; } // -------------------------------------------------------------------------------- -- cgit v1.2.3 From d85464bb3304a112f1dd766428889a919c5715e2 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Mon, 24 May 2010 16:21:56 +0100 Subject: EXT-7138 WIP Don't rebuild the voice effect combo list every time a different effect is selected. Added a notification on receiving new voice effects. --- indra/newview/llvoicevivox.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 070e4f0d2d..17f4b661be 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6857,6 +6857,13 @@ void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const st } mVoiceFontsReceived = true; + // If new Voice Fonts have been found notify the user. + if (mVoiceFontsNew) + { + LLNotificationsUtil::add("VoiceEffectsNew"); + mVoiceFontsNew = false; + } + notifyVoiceFontObservers(true); } -- cgit v1.2.3 From 80b9e6b3fb5086a8d4506a95787a9e84d0e46fb8 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Wed, 26 May 2010 12:55:30 +0100 Subject: EXT-7138 WIP Improved debug logging around voice font expiry --- indra/newview/llvoicevivox.cpp | 54 ++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 20 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 17f4b661be..9ce6ae521e 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6551,35 +6551,36 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, voice_font_map_t::iterator iter = font_map.find(font_id); bool new_font = (iter == font_map.end()); - // If it is a new (unexpired) font create a new entry, otherwise update the existing one. if (new_font) { - if (!has_expired) - { - font = new voiceFontEntry(font_id); - } - else + if (has_expired) { - LL_DEBUGS("Voice") << (template_font?"Template: ":"") << font_id - << " (" << font_index << ") : " << name << " has expired." << LL_ENDL; + // If it's new and already marked expired, ignore it. + return; } + // If it is a new (unexpired) font create a new entry. + font = new voiceFontEntry(font_id); } else { + // Not a new font, update the existing entry font = iter->second; } if (font) { - // Remove fonts that have expired since we last saw them. + // Remove existing fonts that have expired since we last saw them. if (has_expired) { - LL_DEBUGS("Voice") << (template_font?"Template: ":"") << font_id - << " (" << font_index << ") : " << name << " has expired, removing." - << LL_ENDL; + LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template: " : ":") + << font->mExpirationDate.asString() << font_id + << " (" << font_index << ") " << name << LL_ENDL; - deleteVoiceFont(font_id); + if (!template_font) + { + deleteVoiceFont(font_id); + } return; } @@ -6591,10 +6592,22 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, font->mFontType = font_type; font->mFontStatus = font_status; + LL_DEBUGS("Voice") << (template_font ? "Template: " : "") + << font->mExpirationDate.asString() << font->mID + << " (" << font->mFontIndex << ") " << name << LL_ENDL; + // Set the expiry timer to trigger a notification when the voice font can no longer be used. font->mExpiryTimer.start(); font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch()); + if (font->mExpiryTimer.hasExpired()) + { + // Should never happen, but check anyway. + LL_DEBUGS("Voice") << "Voice font " << font->mID + << " expired " << font->mExpirationDate.asString() + << " but is not marked expired!" << LL_ENDL; + } + // Set the warning timer to some interval before actual expiry. S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime"); if (warning_time != 0) @@ -6624,9 +6637,6 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, // Debugging stuff - LL_DEBUGS("Voice") << (template_font?"Template: ":"") << font_id - << " (" << font_index << ") : " << name << 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; @@ -6717,6 +6727,7 @@ void LLVivoxVoiceClient::deleteVoiceFont(const LLUUID& id) { if (list_iter->second == id) { + LL_DEBUGS("Voice") << "Removing " << id << " from the voice font list." << LL_ENDL; mVoiceFontList.erase(list_iter++); } else @@ -6884,6 +6895,8 @@ void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer) void LLVivoxVoiceClient::notifyVoiceFontObservers(bool lists_changed) { + LL_DEBUGS("Voice") << "Notifying voice effect observers. Lists changed: " << lists_changed << LL_ENDL; + for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin(); it != mVoiceFontObservers.end(); ) @@ -7504,8 +7517,9 @@ LLDate LLVivoxProtocolParser::vivoxTimeStampToLLDate(const std::string& vivox_ts { LLDate ts; - // First check to see if it actually already is a parseable ISO8601 date, - // in case the format miraculously changes in future ;) + // First check to see if it actually already is an ISO 8601 date that + // LLDate::fromString() can parse. + // In case the format miraculously changes in future ;) if (ts.fromString(vivox_ts)) { return ts; @@ -7527,8 +7541,8 @@ LLDate LLVivoxProtocolParser::vivoxTimeStampToLLDate(const std::string& vivox_ts ts.fromString(time_stamp); if(!ts.fromString(time_stamp)) { - LL_WARNS_ONCE("Voice") << "Failed to parse Vivox timestamp: " << vivox_ts - << " to ISO 8601 date: " << time_stamp << LL_ENDL; + LL_WARNS_ONCE("VivoxProtocolParser") << "Failed to parse Vivox timestamp: " + << vivox_ts << " to ISO 8601 date: " << time_stamp << LL_ENDL; return LLDate(); } -- cgit v1.2.3 From 3c7df727eeb10a1e6adf27b7aa352afddfcd5d6d Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Wed, 26 May 2010 14:42:18 +0100 Subject: EXT-7138 WIP Simplify and improve detection and notification of changes to the Voice font list --- indra/newview/llvoicevivox.cpp | 98 +++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 48 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 9ce6ae521e..c8e4630e24 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -348,6 +348,7 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mVoiceFontsReceived(false), mVoiceFontsNew(false), + mVoiceFontListDirty(false), mCaptureBufferMode(false), mCaptureBufferRecording(false), @@ -1173,7 +1174,7 @@ void LLVivoxVoiceClient::stateMachine() mCaptureTimer.setTimerExpirySec(CAPTURE_BUFFER_MAX_TIME); // Update UI, should really use a separate callback. - notifyVoiceFontObservers(false); + notifyVoiceFontObservers(); setState(stateCaptureBufferRecording); break; @@ -1188,7 +1189,7 @@ void LLVivoxVoiceClient::stateMachine() mCaptureBufferRecording = false; // Update UI, should really use a separate callback. - notifyVoiceFontObservers(false); + notifyVoiceFontObservers(); setState(stateCaptureBufferPaused); } @@ -1202,7 +1203,7 @@ void LLVivoxVoiceClient::stateMachine() mPreviewVoiceFontLast = mPreviewVoiceFont; // Update UI, should really use a separate callback. - notifyVoiceFontObservers(false); + notifyVoiceFontObservers(); setState(stateCaptureBufferPlaying); break; @@ -1221,7 +1222,7 @@ void LLVivoxVoiceClient::stateMachine() mCaptureBufferPlaying = false; // Update UI, should really use a separate callback. - notifyVoiceFontObservers(false); + notifyVoiceFontObservers(); setState(stateCaptureBufferPaused); } @@ -1769,7 +1770,7 @@ void LLVivoxVoiceClient::stateMachine() { mAudioSessionChanged = false; notifyParticipantObservers(); - notifyVoiceFontObservers(false); + notifyVoiceFontObservers(); } else if (mAudioSession && mAudioSession->mParticipantsChanged) { @@ -6442,7 +6443,7 @@ bool LLVivoxVoiceClient::setVoiceEffect(const LLUUID& id) gSavedPerAccountSettings.setString("VoiceEffectDefault", id.asString()); sessionSetVoiceFontSendMessage(mAudioSession); - notifyVoiceFontObservers(false); + notifyVoiceFontObservers(); return true; } @@ -6551,15 +6552,26 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, voice_font_map_t::iterator iter = font_map.find(font_id); bool new_font = (iter == font_map.end()); - if (new_font) + if (has_expired) { - if (has_expired) + // Remove existing session fonts that have expired since we last saw them. + if (!new_font) { - // If it's new and already marked expired, ignore it. - return; + LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template " : "") + << expiration_date.asString() << " " << font_id + << " (" << font_index << ") " << name << LL_ENDL; + + if (!template_font) + { + deleteVoiceFont(font_id); + } } + return; + } - // If it is a new (unexpired) font create a new entry. + if (new_font) + { + // If it is a new font create a new entry. font = new voiceFontEntry(font_id); } else @@ -6570,20 +6582,6 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, if (font) { - // Remove existing fonts that have expired since we last saw them. - if (has_expired) - { - LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template: " : ":") - << font->mExpirationDate.asString() << font_id - << " (" << font_index << ") " << name << LL_ENDL; - - if (!template_font) - { - deleteVoiceFont(font_id); - } - return; - } - font->mFontIndex = font_index; // Use the description for the human readable name if available, as the // "name" may be a UUID. @@ -6592,8 +6590,8 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, font->mFontType = font_type; font->mFontStatus = font_status; - LL_DEBUGS("Voice") << (template_font ? "Template: " : "") - << font->mExpirationDate.asString() << font->mID + LL_DEBUGS("Voice") << (template_font ? "Template " : "") + << font->mExpirationDate.asString() << " " << font->mID << " (" << font->mFontIndex << ") " << name << LL_ENDL; // Set the expiry timer to trigger a notification when the voice font can no longer be used. @@ -6622,7 +6620,7 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, font->mExpiryWarningTimer.stop(); } - // Only flag it as a new font if we have already seen the font list. + // Only flag new session fonts. if (!template_font && mVoiceFontsReceived && new_font) { font->mIsNew = true; @@ -6635,6 +6633,8 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, font_list.insert(voice_effect_list_t::value_type(font->mName, font->mID)); } + mVoiceFontListDirty = true; + // Debugging stuff if (font_type < VOICE_FONT_TYPE_NONE || font_type >= VOICE_FONT_TYPE_UNKNOWN) @@ -6706,7 +6706,7 @@ void LLVivoxVoiceClient::expireVoiceFonts() } // Refresh voice font lists in the UI. - notifyVoiceFontObservers(true); + notifyVoiceFontObservers(); } // Give a warning notification if any voice fonts are due to expire. @@ -6729,6 +6729,7 @@ void LLVivoxVoiceClient::deleteVoiceFont(const LLUUID& id) { LL_DEBUGS("Voice") << "Removing " << id << " from the voice font list." << LL_ENDL; mVoiceFontList.erase(list_iter++); + mVoiceFontListDirty = true; } else { @@ -6866,22 +6867,15 @@ void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const st { setState(stateVoiceFontsReceived); } - mVoiceFontsReceived = true; - - // If new Voice Fonts have been found notify the user. - if (mVoiceFontsNew) - { - LLNotificationsUtil::add("VoiceEffectsNew"); - mVoiceFontsNew = false; - } - notifyVoiceFontObservers(true); + notifyVoiceFontObservers(); + mVoiceFontsReceived = true; } void LLVivoxVoiceClient::accountGetTemplateFontsResponse(int statusCode, const std::string &statusString) { // Voice font list entries were updated via addVoiceFont() during parsing. - notifyVoiceFontObservers(true); + notifyVoiceFontObservers(); } void LLVivoxVoiceClient::addObserver(LLVoiceEffectObserver* observer) { @@ -6893,19 +6887,30 @@ void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer) mVoiceFontObservers.erase(observer); } -void LLVivoxVoiceClient::notifyVoiceFontObservers(bool lists_changed) +void LLVivoxVoiceClient::notifyVoiceFontObservers() { - LL_DEBUGS("Voice") << "Notifying voice effect observers. Lists changed: " << lists_changed << LL_ENDL; + LL_DEBUGS("Voice") << "Notifying voice effect observers. Lists changed: " << mVoiceFontListDirty << LL_ENDL; for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin(); it != mVoiceFontObservers.end(); ) { LLVoiceEffectObserver* observer = *it; - observer->onVoiceEffectChanged(lists_changed); + observer->onVoiceEffectChanged(mVoiceFontListDirty); // In case onVoiceEffectChanged() deleted an entry. it = mVoiceFontObservers.upper_bound(observer); } + mVoiceFontListDirty = false; + + // If new Voice Fonts have been added notify the user. + if (mVoiceFontsNew) + { + if(mVoiceFontsReceived) + { + LLNotificationsUtil::add("VoiceEffectsNew"); + } + mVoiceFontsNew = false; + } } void LLVivoxVoiceClient::enablePreviewBuffer(bool enable) @@ -7528,14 +7533,11 @@ LLDate LLVivoxProtocolParser::vivoxTimeStampToLLDate(const std::string& vivox_ts std::string time_stamp = vivox_ts; // Vivox's format is missing a T from being standard ISO 8601, - // so add it. It is the only space in their result. + // so add it instead of the only space after the date. LLStringUtil::replaceChar(time_stamp, ' ', 'T'); - // Also need to remove the hours away from GMT to be compatible - // with LLDate, as well as the fractions of seconds. - time_stamp = time_stamp.substr(0, time_stamp.length() - 5); - - // It also needs a 'Z' at the end + // LLDate can't handle offsets from UTC, so remove it, and add a Z + time_stamp = time_stamp.substr(0, time_stamp.length() - 3); time_stamp += "Z"; ts.fromString(time_stamp); -- cgit v1.2.3 From 83ae00daa81d03e3c52cc8bda116803b56979a97 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Thu, 27 May 2010 16:43:59 +0100 Subject: EXT-7138 WIP Use fixed time of day for expiry of Voice Fonts, as the timestamp from Vivox is incorrect. Will need the correct time specifying as VOICE_FONT_EXPIRY_TIME when know what it is from Vivox. Enforce expiry times rather than just relying on the flag from Vivox to avoid ambiguity. Only set expiry timers on adding new fonts, or if the expiry time has changed, to avoid unnecessary notifications. --- indra/newview/llvoicevivox.cpp | 136 ++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 75 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index c8e4630e24..9311f3ba78 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -97,11 +97,14 @@ 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; -// How often to check for expired voice fonts -const F32 VOICE_FONT_EXPIRY_INTERVAL = 1.f; +// How often to check for expired voice fonts in seconds +const F32 VOICE_FONT_EXPIRY_INTERVAL = 10.f; +// Time of day at which Vivox expires voice font subscriptions. +// Used to replace the time portion of received expiry timestamps. +static const std::string VOICE_FONT_EXPIRY_TIME = "T05:00:00Z"; -// Maximum length of capture buffer recordings -const F32 CAPTURE_BUFFER_MAX_TIME = 15.f; +// Maximum length of capture buffer recordings in seconds. +const F32 CAPTURE_BUFFER_MAX_TIME = 10.f; static int scale_mic_volume(float volume) @@ -6524,7 +6527,7 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, const std::string &name, const std::string &description, const LLDate &expiration_date, - const bool has_expired, + bool has_expired, const S32 font_type, const S32 font_status, const bool template_font) @@ -6552,19 +6555,22 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 font_index, voice_font_map_t::iterator iter = font_map.find(font_id); bool new_font = (iter == font_map.end()); + // Override the has_expired flag if we have passed the expiration_date as a double check. + if (expiration_date.secondsSinceEpoch() < (LLDate::now().secondsSinceEpoch() + VOICE_FONT_EXPIRY_INTERVAL)) + { + has_expired = true; + } + if (has_expired) { + LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template " : "") + << expiration_date.asString() << " " << font_id + << " (" << font_index << ") " << name << LL_ENDL; + // Remove existing session fonts that have expired since we last saw them. - if (!new_font) + if (!new_font && !template_font) { - LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template " : "") - << expiration_date.asString() << " " << font_id - << " (" << font_index << ") " << name << LL_ENDL; - - if (!template_font) - { - deleteVoiceFont(font_id); - } + deleteVoiceFont(font_id); } return; } @@ -6586,46 +6592,43 @@ void LLVivoxVoiceClient::addVoiceFont(const S32 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->mFontType = font_type; font->mFontStatus = font_status; - LL_DEBUGS("Voice") << (template_font ? "Template " : "") - << font->mExpirationDate.asString() << " " << font->mID - << " (" << font->mFontIndex << ") " << name << LL_ENDL; + // If the font is new or the expiration date has changed the expiry timers need updating. + if (!template_font && (new_font || font->mExpirationDate != expiration_date)) + { + font->mExpirationDate = expiration_date; - // Set the expiry timer to trigger a notification when the voice font can no longer be used. - font->mExpiryTimer.start(); - font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch()); + // Set the expiry timer to trigger a notification when the voice font can no longer be used. + font->mExpiryTimer.start(); + font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch() - VOICE_FONT_EXPIRY_INTERVAL); - if (font->mExpiryTimer.hasExpired()) - { - // Should never happen, but check anyway. - LL_DEBUGS("Voice") << "Voice font " << font->mID - << " expired " << font->mExpirationDate.asString() - << " but is not marked expired!" << LL_ENDL; - } + // Set the warning timer to some interval before actual expiry. + S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime"); + if (warning_time != 0) + { + font->mExpiryWarningTimer.start(); + F64 expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time); + font->mExpiryWarningTimer.setExpiryAt(expiry_time - VOICE_FONT_EXPIRY_INTERVAL); + } + else + { + // Disable the warning timer. + font->mExpiryWarningTimer.stop(); + } - // Set the warning timer to some interval before actual expiry. - S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime"); - if (warning_time != 0) - { - font->mExpiryWarningTimer.start(); - F64 expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time); - font->mExpiryWarningTimer.setExpiryAt(expiry_time); - } - else - { - // Disable the warning timer. - font->mExpiryWarningTimer.stop(); + // Only flag new session fonts after the first time we have fetched the list. + if (mVoiceFontsReceived) + { + font->mIsNew = true; + mVoiceFontsNew = true; + } } - // Only flag new session fonts. - if (!template_font && mVoiceFontsReceived && new_font) - { - font->mIsNew = true; - mVoiceFontsNew = true; - } + LL_DEBUGS("Voice") << (template_font ? "Template " : "") + << font->mExpirationDate.asString() << " " << font->mID + << " (" << font->mFontIndex << ") " << name << LL_ENDL; if (new_font) { @@ -6678,6 +6681,8 @@ void LLVivoxVoiceClient::expireVoiceFonts() setVoiceEffect(LLUUID::null); expired_in_use = true; } + + LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " has expired." << LL_ENDL; deleteVoiceFont(voice_font->mID); have_expired = true; } @@ -6685,6 +6690,7 @@ void LLVivoxVoiceClient::expireVoiceFonts() // Check for voice fonts that will expire in less that the warning time if (warning_timer.getStarted() && warning_timer.hasExpired()) { + LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " will expire soon." << LL_ENDL; will_expire = true; warning_timer.stop(); } @@ -7471,7 +7477,7 @@ void LLVivoxProtocolParser::EndTag(const char *tag) } else if (!stricmp("ExpirationDate", tag)) { - expirationDate = vivoxTimeStampToLLDate(string); + expirationDate = expiryTimeStampToLLDate(string); } else if (!stricmp("Expired", tag)) { @@ -7518,37 +7524,17 @@ void LLVivoxProtocolParser::CharData(const char *buffer, int length) // -------------------------------------------------------------------------------- -LLDate LLVivoxProtocolParser::vivoxTimeStampToLLDate(const std::string& vivox_ts) +LLDate LLVivoxProtocolParser::expiryTimeStampToLLDate(const std::string& vivox_ts) { - LLDate ts; - - // First check to see if it actually already is an ISO 8601 date that - // LLDate::fromString() can parse. - // In case the format miraculously changes in future ;) - if (ts.fromString(vivox_ts)) - { - return ts; - } - - std::string time_stamp = vivox_ts; + // *HACK: Vivox reports the time incorrectly. LLDate also only parses a + // subset of valid ISO 8601 dates (only handles Z, not offsets). + // So just use the date portion and fix the time here. + std::string time_stamp = vivox_ts.substr(0, 10); + time_stamp += VOICE_FONT_EXPIRY_TIME; - // Vivox's format is missing a T from being standard ISO 8601, - // so add it instead of the only space after the date. - LLStringUtil::replaceChar(time_stamp, ' ', 'T'); - - // LLDate can't handle offsets from UTC, so remove it, and add a Z - time_stamp = time_stamp.substr(0, time_stamp.length() - 3); - time_stamp += "Z"; - - ts.fromString(time_stamp); - if(!ts.fromString(time_stamp)) - { - LL_WARNS_ONCE("VivoxProtocolParser") << "Failed to parse Vivox timestamp: " - << vivox_ts << " to ISO 8601 date: " << time_stamp << LL_ENDL; - return LLDate(); - } + LL_DEBUGS("VivoxProtocolParser") << "Vivox timestamp " << vivox_ts << " modified to: " << time_stamp << LL_ENDL; - return ts; + return LLDate(time_stamp); } // -------------------------------------------------------------------------------- -- cgit v1.2.3 From 275581a3855f7c9c593ad314dfa386ceb952169c Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Mon, 7 Jun 2010 13:56:50 -0700 Subject: EXT-7380 - 'Call' and 'Group Call' verb buttons remain enabled on avatar/group profile page after Voice chat was disabled in 'Preferences' There was a missing listener notification when enabling/disabling voice CR (actualy, took code from) Valeriy ProductEngine --- indra/newview/llvoicevivox.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 96bde129ee..39649f0370 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -5287,6 +5287,7 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled) LLVoiceChannel::getCurrentVoiceChannel()->deactivate(); status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED; } + notifyStatusObservers(status); } } -- cgit v1.2.3 From 163b767944caa4b2a474abf93e64eaeac1f02587 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Wed, 9 Jun 2010 15:45:35 -0700 Subject: Fix EXT-7432: if SL exits before SLVoice connection handshake completes, just kill the SLVoice process. Verified this is OK on windows. --- indra/newview/llvoicevivox.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index c6c155f0f0..74d0f0ef4b 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -396,19 +396,16 @@ void LLVivoxVoiceClient::init(LLPumpIO *pump) void LLVivoxVoiceClient::terminate() { - -// leaveAudioSession(); - logout(); - // As of SDK version 4885, this should no longer be necessary. It will linger after the socket close if it needs to. - // ms_sleep(2000); - connectorShutdown(); - closeSocket(); // Need to do this now -- bad things happen if the destructor does it later. - - // This will do unpleasant things on windows. -// killGateway(); - - - + if(mConnected) + { + logout(); + connectorShutdown(); + closeSocket(); // Need to do this now -- bad things happen if the destructor does it later. + } + else + { + killGateway(); + } } const LLVoiceVersionInfo& LLVivoxVoiceClient::getVersion() -- cgit v1.2.3 From 06b0d72efa96b6a0ed665f7cd46f358c48929e7b Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 13 Aug 2010 07:24:57 -0400 Subject: Change license from GPL to LGPL (version 2.1) --- indra/newview/llvoicevivox.cpp | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 4dc9edb247..15729b5175 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -2,31 +2,25 @@ * @file LLVivoxVoiceClient.cpp * @brief Implementation of LLVivoxVoiceClient class which is the interface to the voice client process. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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 + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -- cgit v1.2.3 From da612aa105b4fddb7a5dac371ceb7a440fe8bf06 Mon Sep 17 00:00:00 2001 From: Aimee Linden Date: Sat, 21 Aug 2010 16:40:47 +0100 Subject: CID-370 Checker: UNINIT_CTOR Function: LLVivoxProtocolParser::LLVivoxProtocolParser() File: /indra/newview/llvoicevivox.cpp --- indra/newview/llvoicevivox.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 15729b5175..2e003dd2b8 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -7111,6 +7111,13 @@ void LLVivoxProtocolParser::reset() alias.clear(); numberOfAliases = 0; applicationString.clear(); + id = 0; + nameString.clear(); + descriptionString.clear(); + expirationDate = LLDate(); + hasExpired = false; + fontType = 0; + fontStatus = 0; } //virtual -- cgit v1.2.3 From 48809cb3a9350a0357a0fc710140e2437f3e068e Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Mon, 7 Jun 2010 16:01:10 -0700 Subject: Merge --- indra/newview/llvoicevivox.cpp | 1082 +++------------------------------------- 1 file changed, 78 insertions(+), 1004 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 2e003dd2b8..d6028b78cb 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -2,25 +2,31 @@ * @file LLVivoxVoiceClient.cpp * @brief Implementation of LLVivoxVoiceClient class which is the interface to the voice client process. * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2010, Linden Research, Inc. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. + * 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 * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * 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 * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 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. * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * 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$ */ @@ -54,7 +60,6 @@ #include "llviewerparcelmgr.h" //#include "llfirstuse.h" #include "llspeakers.h" -#include "lltrans.h" #include "llviewerwindow.h" #include "llviewercamera.h" @@ -62,11 +67,15 @@ #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; @@ -91,15 +100,14 @@ 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; -// How often to check for expired voice fonts in seconds -const F32 VOICE_FONT_EXPIRY_INTERVAL = 10.f; -// Time of day at which Vivox expires voice font subscriptions. -// Used to replace the time portion of received expiry timestamps. -static const std::string VOICE_FONT_EXPIRY_TIME = "T05:00:00Z"; - -// Maximum length of capture buffer recordings in seconds. -const F32 CAPTURE_BUFFER_MAX_TIME = 10.f; +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) { @@ -317,7 +325,6 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mBuddyListMapPopulated(false), mBlockRulesListReceived(false), mAutoAcceptRulesListReceived(false), - mCaptureDeviceDirty(false), mRenderDeviceDirty(false), mSpatialCoordsDirty(false), @@ -341,17 +348,10 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mVoiceEnabled(false), mWriteInProgress(false), - mLipSyncEnabled(false), + mLipSyncEnabled(false) + - mVoiceFontsReceived(false), - mVoiceFontsNew(false), - mVoiceFontListDirty(false), - mCaptureBufferMode(false), - mCaptureBufferRecording(false), - mCaptureBufferRecorded(false), - mCaptureBufferPlaying(false), - mPlayRequestCount(0) { mSpeakerVolume = scale_speaker_volume(0); @@ -396,16 +396,19 @@ void LLVivoxVoiceClient::init(LLPumpIO *pump) void LLVivoxVoiceClient::terminate() { - if(mConnected) - { - logout(); - connectorShutdown(); - closeSocket(); // Need to do this now -- bad things happen if the destructor does it later. - } - else - { - killGateway(); - } + +// leaveAudioSession(); + logout(); + // As of SDK version 4885, this should no longer be necessary. It will linger after the socket close if it needs to. + // ms_sleep(2000); + connectorShutdown(); + closeSocket(); // Need to do this now -- bad things happen if the destructor does it later. + + // This will do unpleasant things on windows. +// killGateway(); + + + } const LLVoiceVersionInfo& LLVivoxVoiceClient::getVersion() @@ -651,11 +654,6 @@ 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); @@ -664,8 +662,6 @@ std::string LLVivoxVoiceClient::state2string(LLVivoxVoiceClient::state inState) CASE(stateNeedsLogin); CASE(stateLoggingIn); CASE(stateLoggedIn); - CASE(stateVoiceFontsWait); - CASE(stateVoiceFontsReceived); CASE(stateCreatingSessionGroup); CASE(stateNoChannel); CASE(stateJoiningSession); @@ -779,10 +775,8 @@ void LLVivoxVoiceClient::stateMachine() // Clean up and reset everything. closeSocket(); deleteAllSessions(); - deleteAllBuddies(); - deleteAllVoiceFonts(); - deleteVoiceFontTemplates(); - + deleteAllBuddies(); + mConnectorHandle.clear(); mAccountHandle.clear(); mAccountPassword.clear(); @@ -1132,97 +1126,8 @@ void LLVivoxVoiceClient::stateMachine() } break; - - //MARK: stateCaptureBufferPaused - case stateCaptureBufferPaused: - if (!mCaptureBufferMode) - { - // Leaving capture mode. - - mCaptureBufferRecording = false; - mCaptureBufferRecorded = false; - mCaptureBufferPlaying = false; - - // Return to stateNoChannel to trigger reconnection to a channel. - setState(stateNoChannel); - } - else if (mCaptureBufferRecording) - { - setState(stateCaptureBufferRecStart); - } - else if (mCaptureBufferPlaying) - { - setState(stateCaptureBufferPlayStart); - } - break; - - //MARK: stateCaptureBufferRecStart - case stateCaptureBufferRecStart: - captureBufferRecordStartSendMessage(); - - // Flag that something is recorded to allow playback. - mCaptureBufferRecorded = true; - - // Start the timer, recording will be stopped when it expires. - mCaptureTimer.start(); - mCaptureTimer.setTimerExpirySec(CAPTURE_BUFFER_MAX_TIME); - - // Update UI, should really use a separate callback. - notifyVoiceFontObservers(); - - setState(stateCaptureBufferRecording); - break; - - //MARK: stateCaptureBufferRecording - case stateCaptureBufferRecording: - if (!mCaptureBufferMode || !mCaptureBufferRecording || - mCaptureBufferPlaying || mCaptureTimer.hasExpired()) - { - // Stop recording - captureBufferRecordStopSendMessage(); - mCaptureBufferRecording = false; - - // Update UI, should really use a separate callback. - notifyVoiceFontObservers(); - - setState(stateCaptureBufferPaused); - } - break; - - //MARK: stateCaptureBufferPlayStart - case stateCaptureBufferPlayStart: - captureBufferPlayStartSendMessage(mPreviewVoiceFont); - - // Store the voice font being previewed, so that we know to restart if it changes. - mPreviewVoiceFontLast = mPreviewVoiceFont; - - // Update UI, should really use a separate callback. - notifyVoiceFontObservers(); - - setState(stateCaptureBufferPlaying); - break; - - //MARK: stateCaptureBufferPlaying - case stateCaptureBufferPlaying: - if (mCaptureBufferPlaying && mPreviewVoiceFont != mPreviewVoiceFontLast) - { - // If the preview voice font changes, restart playing with the new font. - setState(stateCaptureBufferPlayStart); - } - else if (!mCaptureBufferMode || !mCaptureBufferPlaying || mCaptureBufferRecording) - { - // Stop playing. - captureBufferPlayStopSendMessage(); - mCaptureBufferPlaying = false; - - // Update UI, should really use a separate callback. - notifyVoiceFontObservers(); - - setState(stateCaptureBufferPaused); - } - break; - - //MARK: stateConnectorStart + + //MARK: stateConnectorStart case stateConnectorStart: if(!mVoiceEnabled) { @@ -1317,18 +1222,6 @@ void LLVivoxVoiceClient::stateMachine() notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN); - if (LLVoiceClient::instance().getVoiceEffectEnabled()) - { - // Request the set of available voice fonts. - setState(stateVoiceFontsWait); - refreshVoiceEffectLists(true); - } - else - { - // If voice effects are disabled, pretend we've received them and carry on. - setState(stateVoiceFontsReceived); - } - // request the current set of block rules (we'll need them when updating the friends list) accountListBlockRulesSendMessage(); @@ -1360,25 +1253,12 @@ 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 - // Set up the timer to check for expiring voice fonts - mVoiceFontExpiryTimer.start(); - mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL); - #if USE_SESSION_GROUPS // create the main session group - setState(stateCreatingSessionGroup); sessionGroupCreateSendMessage(); + + setState(stateCreatingSessionGroup); #else // Not using session groups -- skip the stateCreatingSessionGroup state. setState(stateNoChannel); @@ -1426,10 +1306,6 @@ void LLVivoxVoiceClient::stateMachine() mTuningExitState = stateNoChannel; setState(stateMicTuningStart); } - else if(mCaptureBufferMode) - { - setState(stateCaptureBufferPaused); - } else if(sessionNeedsRelog(mNextAudioSession)) { requestRelog(); @@ -1440,7 +1316,6 @@ void LLVivoxVoiceClient::stateMachine() sessionState *oldSession = mAudioSession; mAudioSession = mNextAudioSession; - mAudioSessionChanged = true; if(!mAudioSession->mReconnect) { mNextAudioSession = NULL; @@ -1603,13 +1478,6 @@ void LLVivoxVoiceClient::stateMachine() enforceTether(); } - // Do notifications for expiring Voice Fonts. - if (mVoiceFontExpiryTimer.hasExpired()) - { - expireVoiceFonts(); - mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL); - } - // Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often // -- the user can only click so fast) or every 10hz, whichever is sooner. // Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged. @@ -1679,8 +1547,6 @@ void LLVivoxVoiceClient::stateMachine() mAccountHandle.clear(); deleteAllSessions(); deleteAllBuddies(); - deleteAllVoiceFonts(); - deleteVoiceFontTemplates(); if(mVoiceEnabled && !mRelogRequested) { @@ -1761,15 +1627,15 @@ void LLVivoxVoiceClient::stateMachine() } - if (mAudioSessionChanged) + if(mAudioSession && mAudioSession->mParticipantsChanged) { - mAudioSessionChanged = false; - notifyParticipantObservers(); - notifyVoiceFontObservers(); + mAudioSession->mParticipantsChanged = false; + mAudioSessionChanged = true; } - else if (mAudioSession && mAudioSession->mParticipantsChanged) + + if(mAudioSessionChanged) { - mAudioSession->mParticipantsChanged = false; + mAudioSessionChanged = false; notifyParticipantObservers(); } } @@ -1885,11 +1751,8 @@ void LLVivoxVoiceClient::sessionGroupCreateSendMessage() void LLVivoxVoiceClient::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") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL; - + LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL; + session->mCreateInProgress = true; if(startAudio) { @@ -1913,11 +1776,10 @@ void LLVivoxVoiceClient::sessionCreateSendMessage(sessionState *session, bool st << "" << LLURI::escape(session->mHash, allowed_chars) << "" << "SHA1UserName"; } - + stream << "" << (startAudio?"true":"false") << "" << "" << (startText?"true":"false") << "" - << "" << font_index << "" << "" << mChannelName << "" << "\n\n\n"; writeString(stream.str()); @@ -1925,11 +1787,8 @@ 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; - - S32 font_index = getVoiceFontIndex(session->mVoiceFontID); - LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL; - + LL_DEBUGS("Voice") << "requesting create: " << session->mSIPURI << LL_ENDL; + session->mCreateInProgress = true; if(startAudio) { @@ -1955,7 +1814,6 @@ void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session << "" << mChannelName << "" << "" << (startAudio?"true":"false") << "" << "" << (startText?"true":"false") << "" - << "" << font_index << "" << "" << password << "" << "SHA1UserName" << "\n\n\n" @@ -1966,10 +1824,7 @@ void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(sessionState *session void LLVivoxVoiceClient::sessionMediaConnectSendMessage(sessionState *session) { - 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; + LL_DEBUGS("Voice") << "connecting audio to session handle: " << session->mHandle << LL_ENDL; session->mMediaConnectInProgress = true; @@ -1979,7 +1834,6 @@ void LLVivoxVoiceClient::sessionMediaConnectSendMessage(sessionState *session) << "mHandle << "\" action=\"Session.MediaConnect.1\">" << "" << session->mGroupHandle << "" << "" << session->mHandle << "" - << "" << font_index << "" << "Audio" << "\n\n\n"; @@ -3302,7 +3156,7 @@ void LLVivoxVoiceClient::sessionAddedEvent( else { LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL; - session->mCallerID.generate(session->mSIPURI); + setUUIDFromStringHash(session->mCallerID, session->mSIPURI); session->mSynthesizedCallerID = true; // Can't look up the name in this case -- we have to extract it from the URI. @@ -3580,26 +3434,6 @@ void LLVivoxVoiceClient::accountLoginStateChangeEvent( } } -void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType) -{ - if (mediaCompletionType == "AuxBufferAudioCapture") - { - mCaptureBufferRecording = false; - } - else if (mediaCompletionType == "AuxBufferAudioRender") - { - // Ignore all but the last stop event - if (--mPlayRequestCount <= 0) - { - mCaptureBufferPlaying = false; - } - } - else - { - LL_DEBUGS("Voice") << "Unknown MediaCompletionType: " << mediaCompletionType << LL_ENDL; - } -} - void LLVivoxVoiceClient::mediaStreamUpdatedEvent( std::string &sessionHandle, std::string &sessionGroupHandle, @@ -4308,8 +4142,8 @@ LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParti else { // Create a UUID by hashing the URI, but do NOT set mAvatarIDValid. - // This indicates that the ID will not be in the name cache. - result->mAvatarID.generate(uri); + // This tells code in LLVivoxVoiceClient that the ID will not be in the name cache. + setUUIDFromStringHash(result->mAvatarID, uri); } } @@ -4804,7 +4638,7 @@ BOOL LLVivoxVoiceClient::isOnlineSIP(const LLUUID &id) return result; } -bool LLVivoxVoiceClient::isVoiceWorking() const +bool LLVivoxVoiceClient::isVoiceWorking() { //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 @@ -5826,12 +5660,7 @@ 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()) @@ -6256,8 +6085,8 @@ void LLVivoxVoiceClient::notifyParticipantObservers() ) { LLVoiceClientParticipantObserver* observer = *it; - observer->onParticipantsChanged(); - // In case onParticipantsChanged() deleted an entry. + observer->onChange(); + // In case onChange() deleted an entry. it = mParticipantObservers.upper_bound(observer); } } @@ -6420,660 +6249,6 @@ 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["expiry_date"] = font->mExpirationDate; - sd["is_new"] = font->mIsNew; - - return sd; -} - -LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) : - mID(id), - mFontIndex(0), - mFontType(VOICE_FONT_TYPE_NONE), - mFontStatus(VOICE_FONT_STATUS_NONE), - mIsNew(false) -{ - mExpiryTimer.stop(); - mExpiryWarningTimer.stop(); -} - -LLVivoxVoiceClient::voiceFontEntry::~voiceFontEntry() -{ -} - -void LLVivoxVoiceClient::refreshVoiceEffectLists(bool clear_lists) -{ - if (clear_lists) - { - mVoiceFontsReceived = false; - deleteAllVoiceFonts(); - 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 LLDate &expiration_date, - 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. - voice_font_map_t::iterator iter = font_map.find(font_id); - bool new_font = (iter == font_map.end()); - - // Override the has_expired flag if we have passed the expiration_date as a double check. - if (expiration_date.secondsSinceEpoch() < (LLDate::now().secondsSinceEpoch() + VOICE_FONT_EXPIRY_INTERVAL)) - { - has_expired = true; - } - - if (has_expired) - { - LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template " : "") - << expiration_date.asString() << " " << font_id - << " (" << font_index << ") " << name << LL_ENDL; - - // Remove existing session fonts that have expired since we last saw them. - if (!new_font && !template_font) - { - deleteVoiceFont(font_id); - } - return; - } - - if (new_font) - { - // If it is a new font create a new entry. - font = new voiceFontEntry(font_id); - } - else - { - // Not a new font, update the existing entry - 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->mFontType = font_type; - font->mFontStatus = font_status; - - // If the font is new or the expiration date has changed the expiry timers need updating. - if (!template_font && (new_font || font->mExpirationDate != expiration_date)) - { - font->mExpirationDate = expiration_date; - - // Set the expiry timer to trigger a notification when the voice font can no longer be used. - font->mExpiryTimer.start(); - font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch() - VOICE_FONT_EXPIRY_INTERVAL); - - // Set the warning timer to some interval before actual expiry. - S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime"); - if (warning_time != 0) - { - font->mExpiryWarningTimer.start(); - F64 expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time); - font->mExpiryWarningTimer.setExpiryAt(expiry_time - VOICE_FONT_EXPIRY_INTERVAL); - } - else - { - // Disable the warning timer. - font->mExpiryWarningTimer.stop(); - } - - // Only flag new session fonts after the first time we have fetched the list. - if (mVoiceFontsReceived) - { - font->mIsNew = true; - mVoiceFontsNew = true; - } - } - - LL_DEBUGS("Voice") << (template_font ? "Template " : "") - << font->mExpirationDate.asString() << " " << font->mID - << " (" << font->mFontIndex << ") " << name << 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)); - } - - mVoiceFontListDirty = true; - - // Debugging stuff - - 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; - } - } -} - -void LLVivoxVoiceClient::expireVoiceFonts() -{ - // *TODO: If we are selling voice fonts in packs, there are probably - // going to be a number of fonts with the same expiration time, so would - // be more efficient to just keep a list of expiration times rather - // than checking each font individually. - - bool have_expired = false; - bool will_expire = false; - bool expired_in_use = false; - - LLUUID current_effect = LLVoiceClient::instance().getVoiceEffectDefault(); - - voice_font_map_t::iterator iter; - for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter) - { - voiceFontEntry* voice_font = iter->second; - LLFrameTimer& expiry_timer = voice_font->mExpiryTimer; - LLFrameTimer& warning_timer = voice_font->mExpiryWarningTimer; - - // Check for expired voice fonts - if (expiry_timer.getStarted() && expiry_timer.hasExpired()) - { - // Check whether it is the active voice font - if (voice_font->mID == current_effect) - { - // Reset to no voice effect. - setVoiceEffect(LLUUID::null); - expired_in_use = true; - } - - LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " has expired." << LL_ENDL; - deleteVoiceFont(voice_font->mID); - have_expired = true; - } - - // Check for voice fonts that will expire in less that the warning time - if (warning_timer.getStarted() && warning_timer.hasExpired()) - { - LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " will expire soon." << LL_ENDL; - will_expire = true; - warning_timer.stop(); - } - } - - LLSD args; - args["URL"] = LLTrans::getString("voice_morphing_url"); - - // Give a notification if any voice fonts have expired. - if (have_expired) - { - if (expired_in_use) - { - LLNotificationsUtil::add("VoiceEffectsExpiredInUse", args); - } - else - { - LLNotificationsUtil::add("VoiceEffectsExpired", args); - } - - // Refresh voice font lists in the UI. - notifyVoiceFontObservers(); - } - - // Give a warning notification if any voice fonts are due to expire. - if (will_expire) - { - S32 seconds = gSavedSettings.getS32("VoiceEffectExpiryWarningTime"); - args["INTERVAL"] = llformat("%d", seconds / SEC_PER_DAY); - - LLNotificationsUtil::add("VoiceEffectsWillExpire", args); - } -} - -void LLVivoxVoiceClient::deleteVoiceFont(const LLUUID& id) -{ - // Remove the entry from the voice font list. - voice_effect_list_t::iterator list_iter = mVoiceFontList.begin(); - while (list_iter != mVoiceFontList.end()) - { - if (list_iter->second == id) - { - LL_DEBUGS("Voice") << "Removing " << id << " from the voice font list." << LL_ENDL; - mVoiceFontList.erase(list_iter++); - mVoiceFontListDirty = true; - } - else - { - ++list_iter; - } - } - - // Find the entry in the voice font map and erase its data. - voice_font_map_t::iterator map_iter = mVoiceFontMap.find(id); - if (map_iter != mVoiceFontMap.end()) - { - delete map_iter->second; - } - - // Remove the entry from the voice font map. - mVoiceFontMap.erase(map_iter); -} - -void LLVivoxVoiceClient::deleteAllVoiceFonts() -{ - 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 - << "" - << "" << mAccountHandle << "" - << "" - << "\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 - << "" - << "" << mAccountHandle << "" - << "" - << "\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 - << "" - << "" << session->mHandle << "" - << "" << font_index << "" - << "\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(); - mVoiceFontsReceived = true; -} - -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() -{ - LL_DEBUGS("Voice") << "Notifying voice effect observers. Lists changed: " << mVoiceFontListDirty << LL_ENDL; - - for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin(); - it != mVoiceFontObservers.end(); - ) - { - LLVoiceEffectObserver* observer = *it; - observer->onVoiceEffectChanged(mVoiceFontListDirty); - // In case onVoiceEffectChanged() deleted an entry. - it = mVoiceFontObservers.upper_bound(observer); - } - mVoiceFontListDirty = false; - - // If new Voice Fonts have been added notify the user. - if (mVoiceFontsNew) - { - if(mVoiceFontsReceived) - { - LLNotificationsUtil::add("VoiceEffectsNew"); - } - mVoiceFontsNew = false; - } -} - -void LLVivoxVoiceClient::enablePreviewBuffer(bool enable) -{ - mCaptureBufferMode = enable; - if(mCaptureBufferMode && getState() >= stateNoChannel) - { - LL_DEBUGS("Voice") << "no channel" << LL_ENDL; - sessionTerminate(); - } -} - -void LLVivoxVoiceClient::recordPreviewBuffer() -{ - if (!mCaptureBufferMode) - { - LL_DEBUGS("Voice") << "Not in voice effect preview mode, cannot start recording." << LL_ENDL; - mCaptureBufferRecording = false; - return; - } - - mCaptureBufferRecording = true; -} - -void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id) -{ - if (!mCaptureBufferMode) - { - LL_DEBUGS("Voice") << "Not in voice effect preview mode, no buffer to play." << LL_ENDL; - mCaptureBufferRecording = false; - return; - } - - if (!mCaptureBufferRecorded) - { - // Can't play until we have something recorded! - mCaptureBufferPlaying = false; - return; - } - - mPreviewVoiceFont = effect_id; - mCaptureBufferPlaying = true; -} - -void LLVivoxVoiceClient::stopPreviewBuffer() -{ - mCaptureBufferRecording = false; - mCaptureBufferPlaying = false; -} - -bool LLVivoxVoiceClient::isPreviewRecording() -{ - return (mCaptureBufferMode && mCaptureBufferRecording); -} - -bool LLVivoxVoiceClient::isPreviewPlaying() -{ - return (mCaptureBufferMode && mCaptureBufferPlaying); -} - -void LLVivoxVoiceClient::captureBufferRecordStartSendMessage() -{ if(!mAccountHandle.empty()) - { - std::ostringstream stream; - - LL_DEBUGS("Voice") << "Starting audio capture to buffer." << LL_ENDL; - - // Start capture - stream - << "" - << "" - << "\n\n\n"; - - // Unmute the mic - stream << "" - << "" << mConnectorHandle << "" - << "false" - << "\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 << "" - << "" << mConnectorHandle << "" - << "true" - << "\n\n\n"; - - // Stop capture - stream - << "" - << "" << mAccountHandle << "" - << "" - << "\n\n\n"; - - writeString(stream.str()); - } -} - -void LLVivoxVoiceClient::captureBufferPlayStartSendMessage(const LLUUID& voice_font_id) -{ - if(!mAccountHandle.empty()) - { - // Track how may play requests are sent, so we know how many stop events to - // expect before play actually stops. - ++mPlayRequestCount; - - 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 - << "" - << "" << mAccountHandle << "" - << "" << font_index << "" - << "" - << "" - << "\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 - << "" - << "" << mAccountHandle << "" - << "" - << "\n\n\n"; - - writeString(stream.str()); - } -} LLVivoxProtocolParser::LLVivoxProtocolParser() { @@ -7111,13 +6286,6 @@ void LLVivoxProtocolParser::reset() alias.clear(); numberOfAliases = 0; applicationString.clear(); - id = 0; - nameString.clear(); - descriptionString.clear(); - expirationDate = LLDate(); - hasExpired = false; - fontType = 0; - fontStatus = 0; } //virtual @@ -7299,30 +6467,7 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) { LLVivoxVoiceClient::getInstance()->deleteAllAutoAcceptRules(); } - else if (!stricmp("SessionFont", tag)) - { - id = 0; - nameString.clear(); - descriptionString.clear(); - expirationDate = LLDate(); - hasExpired = false; - fontType = 0; - fontStatus = 0; - } - else if (!stricmp("TemplateFont", tag)) - { - id = 0; - nameString.clear(); - descriptionString.clear(); - expirationDate = LLDate(); - hasExpired = false; - fontType = 0; - fontStatus = 0; - } - else if (!stricmp("MediaCompletionType", tag)) - { - mediaCompletionType.clear(); - } + } } responseDepth++; @@ -7468,43 +6613,8 @@ 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, expirationDate, hasExpired, fontType, fontStatus, false); - } - else if (!stricmp("TemplateFont", tag)) - { - LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, 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)) - { - expirationDate = expiryTimeStampToLLDate(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; @@ -7533,21 +6643,6 @@ void LLVivoxProtocolParser::CharData(const char *buffer, int length) // -------------------------------------------------------------------------------- -LLDate LLVivoxProtocolParser::expiryTimeStampToLLDate(const std::string& vivox_ts) -{ - // *HACK: Vivox reports the time incorrectly. LLDate also only parses a - // subset of valid ISO 8601 dates (only handles Z, not offsets). - // So just use the date portion and fix the time here. - std::string time_stamp = vivox_ts.substr(0, 10); - time_stamp += VOICE_FONT_EXPIRY_TIME; - - LL_DEBUGS("VivoxProtocolParser") << "Vivox timestamp " << vivox_ts << " modified to: " << time_stamp << LL_ENDL; - - return LLDate(time_stamp); -} - -// -------------------------------------------------------------------------------- - void LLVivoxProtocolParser::processResponse(std::string tag) { LL_DEBUGS("VivoxProtocolParser") << tag << LL_ENDL; @@ -7601,17 +6696,7 @@ void LLVivoxProtocolParser::processResponse(std::string tag) */ LLVivoxVoiceClient::getInstance()->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming); - } - else if (!stricmp(eventTypeCstr, "MediaCompletionEvent")) - { - /* - - - AuxBufferAudioCapture - - */ - LLVivoxVoiceClient::getInstance()->mediaCompletionEvent(sessionGroupHandle, mediaCompletionType); - } + } else if (!stricmp(eventTypeCstr, "TextStreamUpdatedEvent")) { /* @@ -7672,9 +6757,6 @@ void LLVivoxProtocolParser::processResponse(std::string tag) } else if (!stricmp(eventTypeCstr, "AuxAudioPropertiesEvent")) { - // These are really spammy in tuning mode - squelchDebugOutput = true; - LLVivoxVoiceClient::getInstance()->auxAudioPropertiesEvent(energy); } else if (!stricmp(eventTypeCstr, "BuddyPresenceEvent")) @@ -7789,14 +6871,6 @@ 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")) { -- cgit v1.2.3