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