EXT-7138 FIXED Merge Voice Morphing from aimee/viewer-trunk_voice-features
commit
176b5c5a67
|
|
@ -216,6 +216,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterurldisplay.cpp
|
||||
llfloaterurlentry.cpp
|
||||
llfloatervoicedevicesettings.cpp
|
||||
llfloatervoiceeffect.cpp
|
||||
llfloaterwater.cpp
|
||||
llfloaterwhitelistentry.cpp
|
||||
llfloaterwindlight.cpp
|
||||
|
|
@ -356,6 +357,7 @@ set(viewer_SOURCE_FILES
|
|||
llpanelprofileview.cpp
|
||||
llpanelteleporthistory.cpp
|
||||
llpaneltiptoast.cpp
|
||||
llpanelvoiceeffect.cpp
|
||||
llpanelvolume.cpp
|
||||
llpanelvolumepulldown.cpp
|
||||
llparcelselection.cpp
|
||||
|
|
@ -734,6 +736,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterurldisplay.h
|
||||
llfloaterurlentry.h
|
||||
llfloatervoicedevicesettings.h
|
||||
llfloatervoiceeffect.h
|
||||
llfloaterwater.h
|
||||
llfloaterwhitelistentry.h
|
||||
llfloaterwindlight.h
|
||||
|
|
@ -869,6 +872,7 @@ set(viewer_HEADER_FILES
|
|||
llpanelprofileview.h
|
||||
llpanelteleporthistory.h
|
||||
llpaneltiptoast.h
|
||||
llpanelvoiceeffect.h
|
||||
llpanelvolume.h
|
||||
llpanelvolumepulldown.h
|
||||
llparcelselection.h
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@
|
|||
</array>
|
||||
<key>tags</key>
|
||||
<array>
|
||||
<!-- sample entry for debugging a specific item -->
|
||||
<!-- <string>Voice</string> -->
|
||||
</array>
|
||||
</map>
|
||||
</array>
|
||||
|
|
|
|||
|
|
@ -10606,6 +10606,28 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>VoiceEffectExpiryWarningTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>How much notice to give of Voice Morph subscriptions expiry, in seconds.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>259200</integer>
|
||||
</map>
|
||||
<key>VoiceMorphingEnabled</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not to enable Voice Morphs and show the UI.</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>AutoDisengageMic</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -99,6 +99,17 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>VoiceEffectDefault</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Selected Voice Morph</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>00000000-0000-0000-0000-000000000000</string>
|
||||
</map>
|
||||
|
||||
<!-- Settings below are for back compatibility only.
|
||||
They are not used in current viewer anymore. But they can't be removed to avoid
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static void* create_non_avatar_caller(void*)
|
|||
return new LLNonAvatarCaller;
|
||||
}
|
||||
|
||||
LLVoiceChannel* LLCallFloater::sCurrentVoiceCanel = NULL;
|
||||
LLVoiceChannel* LLCallFloater::sCurrentVoiceChannel = NULL;
|
||||
|
||||
LLCallFloater::LLCallFloater(const LLSD& key)
|
||||
: LLTransientDockableFloater(NULL, false, key)
|
||||
|
|
@ -113,7 +113,7 @@ LLCallFloater::LLCallFloater(const LLSD& key)
|
|||
mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), voice_left_remove_delay);
|
||||
|
||||
mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL);
|
||||
LLVoiceClient::getInstance()->addObserver(this);
|
||||
LLVoiceClient::instance().addObserver(this);
|
||||
LLTransientFloaterMgr::getInstance()->addControlView(this);
|
||||
|
||||
// force docked state since this floater doesn't save it between recreations
|
||||
|
|
@ -158,7 +158,6 @@ BOOL LLCallFloater::postBuild()
|
|||
|
||||
initAgentData();
|
||||
|
||||
|
||||
connectToChannel(LLVoiceChannel::getCurrentVoiceChannel());
|
||||
|
||||
setIsChrome(true);
|
||||
|
|
@ -204,7 +203,7 @@ void LLCallFloater::draw()
|
|||
}
|
||||
|
||||
// virtual
|
||||
void LLCallFloater::onChange()
|
||||
void LLCallFloater::onParticipantsChanged()
|
||||
{
|
||||
if (NULL == mParticipants) return;
|
||||
updateParticipantsVoiceState();
|
||||
|
|
@ -287,22 +286,22 @@ void LLCallFloater::updateSession()
|
|||
|
||||
if (NULL == mSpeakerManager)
|
||||
{
|
||||
// by default let show nearby chat participants
|
||||
// By default show nearby chat participants
|
||||
mSpeakerManager = LLLocalSpeakerMgr::getInstance();
|
||||
LL_DEBUGS("Voice") << "Set DEFAULT speaker manager" << LL_ENDL;
|
||||
mVoiceType = VC_LOCAL_CHAT;
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
|
||||
//hide "Leave Call" button for nearby chat
|
||||
|
||||
// Hide "Leave Call" button for nearby chat
|
||||
bool is_local_chat = mVoiceType == VC_LOCAL_CHAT;
|
||||
childSetVisible("leave_call_btn_panel", !is_local_chat);
|
||||
|
||||
refreshParticipantList();
|
||||
updateAgentModeratorState();
|
||||
|
||||
//show floater for voice calls & only in CONNECTED to voice channel state
|
||||
// Show floater for voice calls & only in CONNECTED to voice channel state
|
||||
if (!is_local_chat &&
|
||||
voice_channel &&
|
||||
LLVoiceChannel::STATE_CONNECTED == voice_channel->getState())
|
||||
|
|
@ -368,7 +367,7 @@ void LLCallFloater::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)
|
|||
// *NOTE: if signal was sent for voice channel with LLVoiceChannel::STATE_NO_CHANNEL_INFO
|
||||
// it sill be sent for the same channel again (when state is changed).
|
||||
// So, lets ignore this call.
|
||||
if (channel == sCurrentVoiceCanel) return;
|
||||
if (channel == sCurrentVoiceChannel) return;
|
||||
|
||||
LLCallFloater* call_floater = LLFloaterReg::getTypedInstance<LLCallFloater>("voice_controls");
|
||||
|
||||
|
|
@ -715,9 +714,9 @@ void LLCallFloater::connectToChannel(LLVoiceChannel* channel)
|
|||
{
|
||||
mVoiceChannelStateChangeConnection.disconnect();
|
||||
|
||||
sCurrentVoiceCanel = channel;
|
||||
sCurrentVoiceChannel = channel;
|
||||
|
||||
mVoiceChannelStateChangeConnection = sCurrentVoiceCanel->setStateChangedCallback(boost::bind(&LLCallFloater::onVoiceChannelStateChanged, this, _1, _2));
|
||||
mVoiceChannelStateChangeConnection = sCurrentVoiceChannel->setStateChangedCallback(boost::bind(&LLCallFloater::onVoiceChannelStateChanged, this, _1, _2));
|
||||
|
||||
updateState(channel->getState());
|
||||
}
|
||||
|
|
@ -737,7 +736,7 @@ void LLCallFloater::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old
|
|||
|
||||
void LLCallFloater::updateState(const LLVoiceChannel::EState& new_state)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Updating state: " << new_state << ", session name: " << sCurrentVoiceCanel->getSessionName() << LL_ENDL;
|
||||
LL_DEBUGS("Voice") << "Updating state: " << new_state << ", session name: " << sCurrentVoiceChannel->getSessionName() << LL_ENDL;
|
||||
if (LLVoiceChannel::STATE_CONNECTED == new_state)
|
||||
{
|
||||
updateSession();
|
||||
|
|
|
|||
|
|
@ -47,15 +47,15 @@ class LLSpeakerMgr;
|
|||
class LLSpeakersDelayActionsStorage;
|
||||
|
||||
/**
|
||||
* The Voice Control Panel is an ambient window summoned by clicking the flyout chevron on the Speak button.
|
||||
* It can be torn-off and freely positioned onscreen.
|
||||
* The Voice Control Panel is an ambient window summoned by clicking the flyout chevron
|
||||
* on the Speak button. It can be torn-off and freely positioned onscreen.
|
||||
*
|
||||
* When the Resident is engaged in Nearby Voice Chat, the Voice Control Panel provides control over
|
||||
* the Resident's own microphone input volume, the audible volume of each of the other participants,
|
||||
* the Resident's own Voice Morphing settings (if she has subscribed to enable the feature), and Voice Recording.
|
||||
* When the Resident is engaged in Voice Chat, the Voice Control Panel provides control
|
||||
* over the audible volume of each of the other participants, the Resident's own Voice
|
||||
* Morphing settings (if she has subscribed to enable the feature), and Voice Recording.
|
||||
*
|
||||
* When the Resident is engaged in any chat except Nearby Chat, the Voice Control Panel also provides an
|
||||
* 'Leave Call' button to allow the Resident to leave that voice channel.
|
||||
* When the Resident is engaged in any chat except Nearby Chat, the Voice Control Panel
|
||||
* also provides a 'Leave Call' button to allow the Resident to leave that voice channel.
|
||||
*/
|
||||
class LLCallFloater : public LLTransientDockableFloater, LLVoiceClientParticipantObserver
|
||||
{
|
||||
|
|
@ -75,7 +75,7 @@ public:
|
|||
*
|
||||
* Refreshes list to display participants not in voice as disabled.
|
||||
*/
|
||||
/*virtual*/ void onChange();
|
||||
/*virtual*/ void onParticipantsChanged();
|
||||
|
||||
static void sOnCurrentChannelChanged(const LLUUID& session_id);
|
||||
|
||||
|
|
@ -259,7 +259,7 @@ private:
|
|||
*
|
||||
* @see sOnCurrentChannelChanged()
|
||||
*/
|
||||
static LLVoiceChannel* sCurrentVoiceCanel;
|
||||
static LLVoiceChannel* sCurrentVoiceChannel;
|
||||
|
||||
/* virtual */
|
||||
LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::IM; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,288 @@
|
|||
/**
|
||||
* @file llfloatervoiceeffect.cpp
|
||||
* @author Aimee
|
||||
* @brief Selection and preview of voice effect.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloatervoiceeffect.h"
|
||||
|
||||
#include "llscrolllistctrl.h"
|
||||
#include "lltrans.h"
|
||||
#include "llweb.h"
|
||||
|
||||
LLFloaterVoiceEffect::LLFloaterVoiceEffect(const LLSD& key)
|
||||
: LLFloater(key)
|
||||
{
|
||||
mCommitCallbackRegistrar.add("VoiceEffect.Record", boost::bind(&LLFloaterVoiceEffect::onClickRecord, this));
|
||||
mCommitCallbackRegistrar.add("VoiceEffect.Play", boost::bind(&LLFloaterVoiceEffect::onClickPlay, this));
|
||||
mCommitCallbackRegistrar.add("VoiceEffect.Stop", boost::bind(&LLFloaterVoiceEffect::onClickStop, this));
|
||||
// mCommitCallbackRegistrar.add("VoiceEffect.Activate", boost::bind(&LLFloaterVoiceEffect::onClickActivate, this));
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLFloaterVoiceEffect::~LLFloaterVoiceEffect()
|
||||
{
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->removeObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLFloaterVoiceEffect::postBuild()
|
||||
{
|
||||
setDefaultBtn("record_btn");
|
||||
getChild<LLButton>("record_btn")->setFocus(true);
|
||||
childSetTextArg("voice_morphing_link", "[URL]", LLTrans::getString("voice_morphing_url"));
|
||||
|
||||
mVoiceEffectList = getChild<LLScrollListCtrl>("voice_effect_list");
|
||||
if (mVoiceEffectList)
|
||||
{
|
||||
mVoiceEffectList->setCommitCallback(boost::bind(&LLFloaterVoiceEffect::onClickPlay, this));
|
||||
// mVoiceEffectList->setDoubleClickCallback(boost::bind(&LLFloaterVoiceEffect::onClickActivate, this));
|
||||
}
|
||||
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->addObserver(this);
|
||||
|
||||
// Disconnect from the current voice channel ready to record a voice sample for previewing
|
||||
effect_interface->enablePreviewBuffer(true);
|
||||
}
|
||||
|
||||
refreshEffectList();
|
||||
updateControls();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloaterVoiceEffect::onClose(bool app_quitting)
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->enablePreviewBuffer(false);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterVoiceEffect::refreshEffectList()
|
||||
{
|
||||
if (!mVoiceEffectList)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (!effect_interface)
|
||||
{
|
||||
mVoiceEffectList->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Voice")<< "Rebuilding Voice Morph list."<< LL_ENDL;
|
||||
|
||||
// Preserve selected items and scroll position
|
||||
S32 scroll_pos = mVoiceEffectList->getScrollPos();
|
||||
uuid_vec_t selected_items;
|
||||
std::vector<LLScrollListItem*> items = mVoiceEffectList->getAllSelected();
|
||||
for(std::vector<LLScrollListItem*>::const_iterator it = items.begin(); it != items.end(); it++)
|
||||
{
|
||||
selected_items.push_back((*it)->getUUID());
|
||||
}
|
||||
|
||||
mVoiceEffectList->deleteAllItems();
|
||||
|
||||
{
|
||||
// Add the "No Voice Morph" entry
|
||||
LLSD element;
|
||||
|
||||
element["id"] = LLUUID::null;
|
||||
element["columns"][NAME_COLUMN]["column"] = "name";
|
||||
element["columns"][NAME_COLUMN]["value"] = getString("no_voice_effect");
|
||||
element["columns"][NAME_COLUMN]["font"]["style"] = "BOLD";
|
||||
|
||||
LLScrollListItem* sl_item = mVoiceEffectList->addElement(element, ADD_BOTTOM);
|
||||
// *HACK: Copied from llfloatergesture.cpp : ["font"]["style"] does not affect font style :(
|
||||
if(sl_item)
|
||||
{
|
||||
((LLScrollListText*)sl_item->getColumn(0))->setFontStyle(LLFontGL::BOLD);
|
||||
}
|
||||
}
|
||||
|
||||
// Add each Voice Morph template, if there are any (template list includes all usable effects)
|
||||
const voice_effect_list_t& template_list = effect_interface->getVoiceEffectTemplateList();
|
||||
if (!template_list.empty())
|
||||
{
|
||||
for (voice_effect_list_t::const_iterator it = template_list.begin(); it != template_list.end(); ++it)
|
||||
{
|
||||
const LLUUID& effect_id = it->second;
|
||||
std::string effect_name = it->first;
|
||||
|
||||
LLSD effect_properties = effect_interface->getVoiceEffectProperties(effect_id);
|
||||
|
||||
// Tag the active effect.
|
||||
if (effect_id == LLVoiceClient::instance().getVoiceEffectDefault())
|
||||
{
|
||||
effect_name += " " + getString("active_voice_effect");
|
||||
}
|
||||
|
||||
// Tag available effects that are new this session
|
||||
if (effect_properties["is_new"].asBoolean())
|
||||
{
|
||||
effect_name += " " + getString("new_voice_effect");
|
||||
}
|
||||
|
||||
LLDate expiry_date = effect_properties["expiry_date"].asDate();
|
||||
bool is_template_only = effect_properties["template_only"].asBoolean();
|
||||
|
||||
std::string font_style = "NORMAL";
|
||||
if (!is_template_only)
|
||||
{
|
||||
font_style = "BOLD";
|
||||
}
|
||||
|
||||
LLSD element;
|
||||
element["id"] = effect_id;
|
||||
|
||||
element["columns"][NAME_COLUMN]["column"] = "name";
|
||||
element["columns"][NAME_COLUMN]["value"] = effect_name;
|
||||
element["columns"][NAME_COLUMN]["font"]["style"] = font_style;
|
||||
|
||||
element["columns"][1]["column"] = "expires";
|
||||
if (!is_template_only)
|
||||
{
|
||||
element["columns"][DATE_COLUMN]["value"] = expiry_date;
|
||||
element["columns"][DATE_COLUMN]["type"] = "date";
|
||||
}
|
||||
else {
|
||||
element["columns"][DATE_COLUMN]["value"] = getString("unsubscribed_voice_effect");
|
||||
}
|
||||
// element["columns"][DATE_COLUMN]["font"]["style"] = "NORMAL";
|
||||
|
||||
LLScrollListItem* sl_item = mVoiceEffectList->addElement(element, ADD_BOTTOM);
|
||||
// *HACK: Copied from llfloatergesture.cpp : ["font"]["style"] does not affect font style :(
|
||||
if(sl_item)
|
||||
{
|
||||
LLFontGL::StyleFlags style = is_template_only ? LLFontGL::NORMAL : LLFontGL::BOLD;
|
||||
dynamic_cast<LLScrollListText*>(sl_item->getColumn(0))->setFontStyle(style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-select items that were selected before, and restore the scroll position
|
||||
for(uuid_vec_t::iterator it = selected_items.begin(); it != selected_items.end(); it++)
|
||||
{
|
||||
mVoiceEffectList->selectByID(*it);
|
||||
}
|
||||
mVoiceEffectList->setScrollPos(scroll_pos);
|
||||
mVoiceEffectList->setEnabled(true);
|
||||
}
|
||||
|
||||
void LLFloaterVoiceEffect::updateControls()
|
||||
{
|
||||
bool recording = false;
|
||||
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
recording = effect_interface->isPreviewRecording();
|
||||
}
|
||||
|
||||
getChild<LLButton>("record_btn")->setVisible(!recording);
|
||||
getChild<LLButton>("record_stop_btn")->setVisible(recording);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloaterVoiceEffect::onVoiceEffectChanged(bool effect_list_updated)
|
||||
{
|
||||
if (effect_list_updated)
|
||||
{
|
||||
refreshEffectList();
|
||||
}
|
||||
updateControls();
|
||||
}
|
||||
|
||||
void LLFloaterVoiceEffect::onClickRecord()
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Record clicked" << LL_ENDL;
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->recordPreviewBuffer();
|
||||
}
|
||||
updateControls();
|
||||
}
|
||||
|
||||
void LLFloaterVoiceEffect::onClickPlay()
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Play clicked" << LL_ENDL;
|
||||
if (!mVoiceEffectList)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const LLUUID& effect_id = mVoiceEffectList->getCurrentID();
|
||||
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->playPreviewBuffer(effect_id);
|
||||
}
|
||||
updateControls();
|
||||
}
|
||||
|
||||
void LLFloaterVoiceEffect::onClickStop()
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Stop clicked" << LL_ENDL;
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->stopPreviewBuffer();
|
||||
}
|
||||
updateControls();
|
||||
}
|
||||
|
||||
//void LLFloaterVoiceEffect::onClickActivate()
|
||||
//{
|
||||
// LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
// if (effect_interface && mVoiceEffectList)
|
||||
// {
|
||||
// effect_interface->setVoiceEffect(mVoiceEffectList->getCurrentID());
|
||||
// }
|
||||
//}
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* @file llfloatervoiceeffect.h
|
||||
* @author Aimee
|
||||
* @brief Selection and preview of voice effects.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERVOICEEFFECT_H
|
||||
#define LL_LLFLOATERVOICEEFFECT_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llvoiceclient.h"
|
||||
|
||||
class LLButton;
|
||||
class LLScrollListCtrl;
|
||||
|
||||
class LLFloaterVoiceEffect
|
||||
: public LLFloater
|
||||
, public LLVoiceEffectObserver
|
||||
{
|
||||
public:
|
||||
LOG_CLASS(LLFloaterVoiceEffect);
|
||||
|
||||
LLFloaterVoiceEffect(const LLSD& key);
|
||||
virtual ~LLFloaterVoiceEffect();
|
||||
|
||||
virtual BOOL postBuild();
|
||||
virtual void onClose(bool app_quitting);
|
||||
|
||||
private:
|
||||
enum ColumnIndex
|
||||
{
|
||||
NAME_COLUMN = 0,
|
||||
DATE_COLUMN = 1,
|
||||
};
|
||||
|
||||
void refreshEffectList();
|
||||
void updateControls();
|
||||
|
||||
/// Called by voice effect provider when voice effect list is changed.
|
||||
virtual void onVoiceEffectChanged(bool effect_list_updated);
|
||||
|
||||
void onClickRecord();
|
||||
void onClickPlay();
|
||||
void onClickStop();
|
||||
// void onClickActivate();
|
||||
|
||||
LLUUID mSelectedID;
|
||||
LLScrollListCtrl* mVoiceEffectList;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* @file llpanelvoiceeffect.cpp
|
||||
* @author Aimee
|
||||
* @brief Panel to select Voice Morphs.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2010, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llpanelvoiceeffect.h"
|
||||
|
||||
#include "llcombobox.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llpanel.h"
|
||||
#include "lltrans.h"
|
||||
#include "lltransientfloatermgr.h"
|
||||
#include "llvoiceclient.h"
|
||||
|
||||
static LLRegisterPanelClassWrapper<LLPanelVoiceEffect> t_panel_voice_effect("panel_voice_effect");
|
||||
|
||||
LLPanelVoiceEffect::LLPanelVoiceEffect()
|
||||
: mVoiceEffectCombo(NULL)
|
||||
{
|
||||
mCommitCallbackRegistrar.add("Voice.CommitVoiceEffect", boost::bind(&LLPanelVoiceEffect::onCommitVoiceEffect, this));
|
||||
}
|
||||
|
||||
LLPanelVoiceEffect::~LLPanelVoiceEffect()
|
||||
{
|
||||
LLView* combo_list_view = mVoiceEffectCombo->getChildView("ComboBox");
|
||||
LLTransientFloaterMgr::getInstance()->removeControlView(combo_list_view);
|
||||
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->removeObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLPanelVoiceEffect::postBuild()
|
||||
{
|
||||
mVoiceEffectCombo = getChild<LLComboBox>("voice_effect");
|
||||
|
||||
// Need to tell LLTransientFloaterMgr about the combo list, otherwise it can't
|
||||
// be clicked while in a docked floater as it extends outside the floater area.
|
||||
LLView* combo_list_view = mVoiceEffectCombo->getChildView("ComboBox");
|
||||
LLTransientFloaterMgr::getInstance()->addControlView(combo_list_view);
|
||||
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (effect_interface)
|
||||
{
|
||||
effect_interface->addObserver(this);
|
||||
}
|
||||
|
||||
update(true);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// PRIVATE SECTION
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void LLPanelVoiceEffect::onCommitVoiceEffect()
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (!effect_interface)
|
||||
{
|
||||
mVoiceEffectCombo->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
LLSD value = mVoiceEffectCombo->getValue();
|
||||
if (value.asInteger() == PREVIEW_VOICE_EFFECTS)
|
||||
{
|
||||
// Open the Voice Morph preview floater
|
||||
LLFloaterReg::showInstance("voice_effect");
|
||||
}
|
||||
else if (value.asInteger() == GET_VOICE_EFFECTS)
|
||||
{
|
||||
// Open the voice morphing info web page
|
||||
LLWeb::loadURL(LLTrans::getString("voice_morphing_url"));
|
||||
}
|
||||
else
|
||||
{
|
||||
effect_interface->setVoiceEffect(value.asUUID());
|
||||
}
|
||||
|
||||
mVoiceEffectCombo->setValue(effect_interface->getVoiceEffect());
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLPanelVoiceEffect::onVoiceEffectChanged(bool effect_list_updated)
|
||||
{
|
||||
update(effect_list_updated);
|
||||
}
|
||||
|
||||
void LLPanelVoiceEffect::update(bool list_updated)
|
||||
{
|
||||
if (mVoiceEffectCombo)
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
if (list_updated)
|
||||
{
|
||||
// Add the default "No Voice Morph" entry.
|
||||
mVoiceEffectCombo->removeall();
|
||||
mVoiceEffectCombo->add(getString("no_voice_effect"), LLUUID::null);
|
||||
mVoiceEffectCombo->addSeparator();
|
||||
|
||||
// Add entries for each Voice Morph.
|
||||
const voice_effect_list_t& effect_list = effect_interface->getVoiceEffectList();
|
||||
if (!effect_list.empty())
|
||||
{
|
||||
for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
|
||||
{
|
||||
mVoiceEffectCombo->add(it->first, it->second, ADD_BOTTOM);
|
||||
}
|
||||
|
||||
mVoiceEffectCombo->addSeparator();
|
||||
}
|
||||
|
||||
// Add the fixed entries to go to the preview floater or marketing page.
|
||||
mVoiceEffectCombo->add(getString("preview_voice_effects"), PREVIEW_VOICE_EFFECTS);
|
||||
mVoiceEffectCombo->add(getString("get_voice_effects"), GET_VOICE_EFFECTS);
|
||||
}
|
||||
|
||||
if (effect_interface && LLVoiceClient::instance().isVoiceWorking())
|
||||
{
|
||||
// Select the current Voice Morph.
|
||||
mVoiceEffectCombo->setValue(effect_interface->getVoiceEffect());
|
||||
mVoiceEffectCombo->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If voice isn't working or Voice Effects are not supported disable the control.
|
||||
mVoiceEffectCombo->setValue(LLUUID::null);
|
||||
mVoiceEffectCombo->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @file llpanelvoiceeffect.h
|
||||
* @author Aimee
|
||||
* @brief Panel to select Voice Effects.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2010, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_PANELVOICEEFFECT_H
|
||||
#define LL_PANELVOICEEFFECT_H
|
||||
|
||||
#include "llpanel.h"
|
||||
#include "llvoiceclient.h"
|
||||
|
||||
class LLComboBox;
|
||||
|
||||
class LLPanelVoiceEffect
|
||||
: public LLPanel
|
||||
, public LLVoiceEffectObserver
|
||||
{
|
||||
public:
|
||||
LOG_CLASS(LLPanelVoiceEffect);
|
||||
|
||||
LLPanelVoiceEffect();
|
||||
virtual ~LLPanelVoiceEffect();
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
private:
|
||||
void onCommitVoiceEffect();
|
||||
void update(bool list_updated);
|
||||
|
||||
/// Called by voice effect provider when voice effect list is changed.
|
||||
virtual void onVoiceEffectChanged(bool effect_list_updated);
|
||||
|
||||
// Fixed entries in the Voice Morph list
|
||||
typedef enum e_voice_effect_combo_items
|
||||
{
|
||||
NO_VOICE_EFFECT = 0,
|
||||
PREVIEW_VOICE_EFFECTS = 1,
|
||||
GET_VOICE_EFFECTS = 2
|
||||
} EVoiceEffectComboItems;
|
||||
|
||||
LLComboBox* mVoiceEffectCombo;
|
||||
};
|
||||
|
||||
|
||||
#endif //LL_PANELVOICEEFFECT_H
|
||||
|
|
@ -94,7 +94,7 @@ public:
|
|||
mAvalineCallers.insert(avaline_caller_id);
|
||||
}
|
||||
|
||||
void onChange()
|
||||
void onParticipantsChanged()
|
||||
{
|
||||
uuid_set_t participant_uuids;
|
||||
LLVoiceClient::getInstance()->getParticipantList(participant_uuids);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ private:
|
|||
* So, method does not calculate difference between these list it only switches off already
|
||||
* switched on indicators and switches on indicators of voice channel participants
|
||||
*/
|
||||
void onChange();
|
||||
void onParticipantsChanged();
|
||||
|
||||
/**
|
||||
* Changes state of indicators specified by LLUUIDs
|
||||
|
|
@ -205,7 +205,7 @@ void SpeakingIndicatorManager::sOnCurrentChannelChanged(const LLUUID& /*session_
|
|||
mSwitchedIndicatorsOn.clear();
|
||||
}
|
||||
|
||||
void SpeakingIndicatorManager::onChange()
|
||||
void SpeakingIndicatorManager::onParticipantsChanged()
|
||||
{
|
||||
LL_DEBUGS("SpeakingIndicator") << "Voice participant list was changed, updating indicators" << LL_ENDL;
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@
|
|||
#include "llfloateruipreview.h"
|
||||
#include "llfloaterurldisplay.h"
|
||||
#include "llfloatervoicedevicesettings.h"
|
||||
#include "llfloatervoiceeffect.h"
|
||||
#include "llfloaterwater.h"
|
||||
#include "llfloaterwhitelistentry.h"
|
||||
#include "llfloaterwindlight.h"
|
||||
|
|
@ -255,7 +256,8 @@ void LLViewerFloaterReg::registerFloaters()
|
|||
LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload");
|
||||
|
||||
LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);
|
||||
|
||||
LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>);
|
||||
|
||||
LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);
|
||||
LLFloaterWindowSizeUtil::registerFloater();
|
||||
LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>);
|
||||
|
|
|
|||
|
|
@ -897,9 +897,9 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s
|
|||
else
|
||||
{
|
||||
LL_WARNS("Voice") << "incoming SIP URL is not provided. Channel may not work properly." << LL_ENDL;
|
||||
// In case of incoming AvaLine call generated URI will be differ from original one.
|
||||
// This is because Avatar-2-Avatar URI is based on avatar UUID but Avaline is not.
|
||||
// See LLVoiceClient::sessionAddedEvent() -> setUUIDFromStringHash()
|
||||
// In the case of an incoming AvaLine call, the generated URI will be different from the
|
||||
// original one. This is because the P2P URI is based on avatar UUID but Avaline is not.
|
||||
// See LLVoiceClient::sessionAddedEvent()
|
||||
setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ protected:
|
|||
void doSetState(const EState& state);
|
||||
void setURI(std::string uri);
|
||||
|
||||
// there can be two directions ICOMING and OUTGOING
|
||||
// there can be two directions INCOMING and OUTGOING
|
||||
EDirection mCallDirection;
|
||||
|
||||
std::string mURI;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "llviewerwindow.h"
|
||||
#include "llvoicevivox.h"
|
||||
#include "llviewernetwork.h"
|
||||
#include "llcommandhandler.h"
|
||||
#include "llhttpnode.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llsdserialize.h"
|
||||
|
|
@ -46,6 +47,39 @@ const F32 LLVoiceClient::VOLUME_MIN = 0.f;
|
|||
const F32 LLVoiceClient::VOLUME_DEFAULT = 0.5f;
|
||||
const F32 LLVoiceClient::VOLUME_MAX = 1.0f;
|
||||
|
||||
|
||||
// Support for secondlife:///app/voice SLapps
|
||||
class LLVoiceHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// requests will be throttled from a non-trusted browser
|
||||
LLVoiceHandler() : LLCommandHandler("voice", UNTRUSTED_THROTTLE) {}
|
||||
|
||||
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
|
||||
{
|
||||
if (params[0].asString() == "effects")
|
||||
{
|
||||
LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
|
||||
// If the voice client doesn't support voice effects, we can't handle effects SLapps
|
||||
if (!effect_interface)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Support secondlife:///app/voice/effects/refresh to update the voice effect list with new effects
|
||||
if (params[1].asString() == "refresh")
|
||||
{
|
||||
effect_interface->refreshVoiceEffectLists(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
LLVoiceHandler gVoiceHandler;
|
||||
|
||||
|
||||
|
||||
std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus)
|
||||
{
|
||||
std::string result = "UNKNOWN";
|
||||
|
|
@ -77,12 +111,13 @@ std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserv
|
|||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLVoiceClient::LLVoiceClient()
|
||||
LLVoiceClient::LLVoiceClient() :
|
||||
mVoiceModule(NULL),
|
||||
mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceMorphingEnabled")),
|
||||
mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault"))
|
||||
{
|
||||
mVoiceModule = NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
|
|
@ -565,7 +600,7 @@ std::string LLVoiceClient::getDisplayName(const LLUUID& id)
|
|||
}
|
||||
}
|
||||
|
||||
bool LLVoiceClient::isVoiceWorking()
|
||||
bool LLVoiceClient::isVoiceWorking() const
|
||||
{
|
||||
if (mVoiceModule)
|
||||
{
|
||||
|
|
@ -708,6 +743,10 @@ std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
|
|||
}
|
||||
}
|
||||
|
||||
LLVoiceEffectInterface* LLVoiceClient::getVoiceEffectInterface() const
|
||||
{
|
||||
return getVoiceEffectEnabled() ? dynamic_cast<LLVoiceEffectInterface*>(mVoiceModule) : NULL;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// version checking
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class LLVOAvatar;
|
|||
#include "llviewerregion.h"
|
||||
#include "llcallingcard.h" // for LLFriendObserver
|
||||
#include "llsecapi.h"
|
||||
#include "llcontrol.h"
|
||||
|
||||
// devices
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ class LLVoiceClientParticipantObserver
|
|||
{
|
||||
public:
|
||||
virtual ~LLVoiceClientParticipantObserver() { }
|
||||
virtual void onChange() = 0;
|
||||
virtual void onParticipantsChanged() = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -109,7 +110,7 @@ public:
|
|||
|
||||
virtual void updateSettings()=0; // call after loading settings and whenever they change
|
||||
|
||||
virtual bool isVoiceWorking()=0; // connected to a voice server and voice channel
|
||||
virtual bool isVoiceWorking() const = 0; // connected to a voice server and voice channel
|
||||
|
||||
virtual const LLVoiceVersionInfo& getVersion()=0;
|
||||
|
||||
|
|
@ -217,8 +218,6 @@ public:
|
|||
//////////////////////////
|
||||
/// @name nearby speaker accessors
|
||||
//@{
|
||||
|
||||
|
||||
virtual BOOL getVoiceEnabled(const LLUUID& id)=0; // true if we've received data for this avatar
|
||||
virtual std::string getDisplayName(const LLUUID& id)=0;
|
||||
virtual BOOL isOnlineSIP(const LLUUID &id)=0;
|
||||
|
|
@ -261,6 +260,63 @@ public:
|
|||
};
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
/// @class LLVoiceEffectObserver
|
||||
class LLVoiceEffectObserver
|
||||
{
|
||||
public:
|
||||
virtual ~LLVoiceEffectObserver() { }
|
||||
virtual void onVoiceEffectChanged(bool effect_list_updated) = 0;
|
||||
};
|
||||
|
||||
typedef std::multimap<const std::string, const LLUUID, LLDictionaryLess> voice_effect_list_t;
|
||||
|
||||
//////////////////////////////////
|
||||
/// @class LLVoiceEffectInterface
|
||||
/// @brief Voice effect module interface
|
||||
///
|
||||
/// Voice effect modules should provide an implementation for this interface.
|
||||
/////////////////////////////////
|
||||
|
||||
class LLVoiceEffectInterface
|
||||
{
|
||||
public:
|
||||
LLVoiceEffectInterface() {}
|
||||
virtual ~LLVoiceEffectInterface() {}
|
||||
|
||||
//////////////////////////
|
||||
/// @name Accessors
|
||||
//@{
|
||||
virtual bool setVoiceEffect(const LLUUID& id) = 0;
|
||||
virtual const LLUUID getVoiceEffect() = 0;
|
||||
virtual LLSD getVoiceEffectProperties(const LLUUID& id) = 0;
|
||||
|
||||
virtual void refreshVoiceEffectLists(bool clear_lists) = 0;
|
||||
virtual const voice_effect_list_t &getVoiceEffectList() const = 0;
|
||||
virtual const voice_effect_list_t &getVoiceEffectTemplateList() const = 0;
|
||||
//@}
|
||||
|
||||
//////////////////////////////
|
||||
/// @name Status notification
|
||||
//@{
|
||||
virtual void addObserver(LLVoiceEffectObserver* observer) = 0;
|
||||
virtual void removeObserver(LLVoiceEffectObserver* observer) = 0;
|
||||
//@}
|
||||
|
||||
//////////////////////////////
|
||||
/// @name Preview buffer
|
||||
//@{
|
||||
virtual void enablePreviewBuffer(bool enable) = 0;
|
||||
virtual void recordPreviewBuffer() = 0;
|
||||
virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null) = 0;
|
||||
virtual void stopPreviewBuffer() = 0;
|
||||
|
||||
virtual bool isPreviewRecording() = 0;
|
||||
virtual bool isPreviewPlaying() = 0;
|
||||
//@}
|
||||
};
|
||||
|
||||
|
||||
class LLVoiceClient: public LLSingleton<LLVoiceClient>
|
||||
{
|
||||
LOG_CLASS(LLVoiceClient);
|
||||
|
|
@ -281,7 +337,7 @@ public:
|
|||
|
||||
void updateSettings(); // call after loading settings and whenever they change
|
||||
|
||||
bool isVoiceWorking(); // connected to a voice server and voice channel
|
||||
bool isVoiceWorking() const; // connected to a voice server and voice channel
|
||||
|
||||
// tuning
|
||||
void tuningStart();
|
||||
|
|
@ -403,10 +459,23 @@ public:
|
|||
void removeObserver(LLVoiceClientParticipantObserver* observer);
|
||||
|
||||
std::string sipURIFromID(const LLUUID &id);
|
||||
|
||||
|
||||
//////////////////////////
|
||||
/// @name Voice effects
|
||||
//@{
|
||||
bool getVoiceEffectEnabled() const { return mVoiceEffectEnabled; };
|
||||
LLUUID getVoiceEffectDefault() const { return LLUUID(mVoiceEffectDefault); };
|
||||
|
||||
// Returns NULL if voice effects are not supported, or not enabled.
|
||||
LLVoiceEffectInterface* getVoiceEffectInterface() const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
LLVoiceModuleInterface* mVoiceModule;
|
||||
LLPumpIO *m_servicePump;
|
||||
|
||||
LLCachedControl<bool> mVoiceEffectEnabled;
|
||||
LLCachedControl<std::string> mVoiceEffectDefault;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -57,15 +57,9 @@ class LLVivoxVoiceClientMuteListObserver;
|
|||
class LLVivoxVoiceClientFriendsObserver;
|
||||
|
||||
|
||||
class LLVivoxVoiceClientParticipantObserver
|
||||
{
|
||||
public:
|
||||
virtual ~LLVivoxVoiceClientParticipantObserver() { }
|
||||
virtual void onChange() = 0;
|
||||
};
|
||||
|
||||
|
||||
class LLVivoxVoiceClient: public LLSingleton<LLVivoxVoiceClient>, virtual public LLVoiceModuleInterface
|
||||
class LLVivoxVoiceClient : public LLSingleton<LLVivoxVoiceClient>,
|
||||
virtual public LLVoiceModuleInterface,
|
||||
virtual public LLVoiceEffectInterface
|
||||
{
|
||||
LOG_CLASS(LLVivoxVoiceClient);
|
||||
public:
|
||||
|
|
@ -84,7 +78,7 @@ public:
|
|||
virtual void updateSettings(); // call after loading settings and whenever they change
|
||||
|
||||
// Returns true if vivox has successfully logged in and is not in error state
|
||||
virtual bool isVoiceWorking();
|
||||
virtual bool isVoiceWorking() const;
|
||||
|
||||
/////////////////////
|
||||
/// @name Tuning
|
||||
|
|
@ -232,15 +226,49 @@ public:
|
|||
virtual void removeObserver(LLFriendObserver* observer);
|
||||
virtual void addObserver(LLVoiceClientParticipantObserver* observer);
|
||||
virtual void removeObserver(LLVoiceClientParticipantObserver* observer);
|
||||
|
||||
|
||||
|
||||
//@}
|
||||
|
||||
virtual std::string sipURIFromID(const LLUUID &id);
|
||||
//@}
|
||||
|
||||
|
||||
/// @name LLVoiceEffectInterface virtual implementations
|
||||
/// @see LLVoiceEffectInterface
|
||||
//@{
|
||||
|
||||
//////////////////////////
|
||||
/// @name Accessors
|
||||
//@{
|
||||
virtual bool setVoiceEffect(const LLUUID& id);
|
||||
virtual const LLUUID getVoiceEffect();
|
||||
virtual LLSD getVoiceEffectProperties(const LLUUID& id);
|
||||
|
||||
virtual void refreshVoiceEffectLists(bool clear_lists);
|
||||
virtual const voice_effect_list_t& getVoiceEffectList() const;
|
||||
virtual const voice_effect_list_t& getVoiceEffectTemplateList() const;
|
||||
//@}
|
||||
|
||||
//////////////////////////////
|
||||
/// @name Status notification
|
||||
//@{
|
||||
virtual void addObserver(LLVoiceEffectObserver* observer);
|
||||
virtual void removeObserver(LLVoiceEffectObserver* observer);
|
||||
//@}
|
||||
|
||||
//////////////////////////////
|
||||
/// @name Effect preview buffer
|
||||
//@{
|
||||
virtual void enablePreviewBuffer(bool enable);
|
||||
virtual void recordPreviewBuffer();
|
||||
virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null);
|
||||
virtual void stopPreviewBuffer();
|
||||
|
||||
virtual bool isPreviewRecording();
|
||||
virtual bool isPreviewPlaying();
|
||||
//@}
|
||||
|
||||
//@}
|
||||
|
||||
|
||||
protected:
|
||||
//////////////////////
|
||||
// Vivox Specific definitions
|
||||
|
|
@ -278,14 +306,13 @@ protected:
|
|||
bool mIsSpeaking;
|
||||
bool mIsModeratorMuted;
|
||||
bool mOnMuteList; // true if this avatar is on the user's mute list (and should be muted)
|
||||
bool mVolumeSet; // true if incoming volume messages should not change the volume
|
||||
bool mVolumeSet; // true if incoming volume messages should not change the volume
|
||||
bool mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed)
|
||||
bool mAvatarIDValid;
|
||||
bool mIsSelf;
|
||||
};
|
||||
|
||||
typedef std::map<const std::string, participantState*> participantMap;
|
||||
|
||||
typedef std::map<const LLUUID, participantState*> participantUUIDMap;
|
||||
|
||||
struct sessionState
|
||||
|
|
@ -332,14 +359,17 @@ protected:
|
|||
bool mIncoming;
|
||||
bool mVoiceEnabled;
|
||||
bool mReconnect; // Whether we should try to reconnect to this session if it's dropped
|
||||
// Set to true when the mute state of someone in the participant list changes.
|
||||
|
||||
// Set to true when the volume/mute state of someone in the participant list changes.
|
||||
// The code will have to walk the list to find the changed participant(s).
|
||||
bool mVolumeDirty;
|
||||
bool mMuteDirty;
|
||||
|
||||
bool mMuteDirty;
|
||||
|
||||
bool mParticipantsChanged;
|
||||
participantMap mParticipantsByURI;
|
||||
participantUUIDMap mParticipantsByUUID;
|
||||
|
||||
LLUUID mVoiceFontID;
|
||||
};
|
||||
|
||||
// internal state for a simple state machine. This is used to deal with the asynchronous nature of some of the messages.
|
||||
|
|
@ -356,6 +386,11 @@ protected:
|
|||
stateMicTuningStart,
|
||||
stateMicTuningRunning,
|
||||
stateMicTuningStop,
|
||||
stateCaptureBufferPaused,
|
||||
stateCaptureBufferRecStart,
|
||||
stateCaptureBufferRecording,
|
||||
stateCaptureBufferPlayStart,
|
||||
stateCaptureBufferPlaying,
|
||||
stateConnectorStart, // connector needs to be started
|
||||
stateConnectorStarting, // waiting for connector handle
|
||||
stateConnectorStarted, // connector handle received
|
||||
|
|
@ -364,6 +399,8 @@ protected:
|
|||
stateNeedsLogin, // send login request
|
||||
stateLoggingIn, // waiting for account handle
|
||||
stateLoggedIn, // account handle received
|
||||
stateVoiceFontsWait, // Awaiting the list of voice fonts
|
||||
stateVoiceFontsReceived, // List of voice fonts received
|
||||
stateCreatingSessionGroup, // Creating the main session group
|
||||
stateNoChannel, //
|
||||
stateJoiningSession, // waiting for session handle
|
||||
|
|
@ -436,8 +473,6 @@ protected:
|
|||
void tuningCaptureStartSendMessage(int duration);
|
||||
void tuningCaptureStopSendMessage();
|
||||
|
||||
bool inTuningStates();
|
||||
|
||||
//----------------------------------
|
||||
// devices
|
||||
void clearCaptureDevices();
|
||||
|
|
@ -464,6 +499,7 @@ protected:
|
|||
void connectorShutdownResponse(int statusCode, std::string &statusString);
|
||||
|
||||
void accountLoginStateChangeEvent(std::string &accountHandle, int statusCode, std::string &statusString, int state);
|
||||
void mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType);
|
||||
void mediaStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, int statusCode, std::string &statusString, int state, bool incoming);
|
||||
void textStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, bool enabled, int state, bool incoming);
|
||||
void sessionAddedEvent(std::string &uriString, std::string &alias, std::string &sessionHandle, std::string &sessionGroupHandle, bool isChannel, bool incoming, std::string &nameString, std::string &applicationString);
|
||||
|
|
@ -591,8 +627,8 @@ protected:
|
|||
void deleteAllAutoAcceptRules(void);
|
||||
void addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy);
|
||||
void accountListBlockRulesResponse(int statusCode, const std::string &statusString);
|
||||
void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString);
|
||||
|
||||
void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString);
|
||||
|
||||
/////////////////////////////
|
||||
// session control messages
|
||||
|
||||
|
|
@ -621,7 +657,21 @@ protected:
|
|||
void lookupName(const LLUUID &id);
|
||||
static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group);
|
||||
void avatarNameResolved(const LLUUID &id, const std::string &name);
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// Voice fonts
|
||||
|
||||
void addVoiceFont(const S32 id,
|
||||
const std::string &name,
|
||||
const std::string &description,
|
||||
const LLDate &expiration_date,
|
||||
bool has_expired,
|
||||
const S32 font_type,
|
||||
const S32 font_status,
|
||||
const bool template_font = false);
|
||||
void accountGetSessionFontsResponse(int statusCode, const std::string &statusString);
|
||||
void accountGetTemplateFontsResponse(int statusCode, const std::string &statusString);
|
||||
|
||||
private:
|
||||
LLVoiceVersionInfo mVoiceVersion;
|
||||
|
||||
|
|
@ -804,6 +854,88 @@ private:
|
|||
typedef std::set<LLFriendObserver*> friend_observer_set_t;
|
||||
friend_observer_set_t mFriendObservers;
|
||||
void notifyFriendObservers();
|
||||
|
||||
// Voice Fonts
|
||||
|
||||
void expireVoiceFonts();
|
||||
void deleteVoiceFont(const LLUUID& id);
|
||||
void deleteAllVoiceFonts();
|
||||
void deleteVoiceFontTemplates();
|
||||
|
||||
S32 getVoiceFontIndex(const LLUUID& id) const;
|
||||
S32 getVoiceFontTemplateIndex(const LLUUID& id) const;
|
||||
|
||||
void accountGetSessionFontsSendMessage();
|
||||
void accountGetTemplateFontsSendMessage();
|
||||
void sessionSetVoiceFontSendMessage(sessionState *session);
|
||||
|
||||
void notifyVoiceFontObservers();
|
||||
|
||||
typedef enum e_voice_font_type
|
||||
{
|
||||
VOICE_FONT_TYPE_NONE = 0,
|
||||
VOICE_FONT_TYPE_ROOT = 1,
|
||||
VOICE_FONT_TYPE_USER = 2,
|
||||
VOICE_FONT_TYPE_UNKNOWN
|
||||
} EVoiceFontType;
|
||||
|
||||
typedef enum e_voice_font_status
|
||||
{
|
||||
VOICE_FONT_STATUS_NONE = 0,
|
||||
VOICE_FONT_STATUS_FREE = 1,
|
||||
VOICE_FONT_STATUS_NOT_FREE = 2,
|
||||
VOICE_FONT_STATUS_UNKNOWN
|
||||
} EVoiceFontStatus;
|
||||
|
||||
struct voiceFontEntry
|
||||
{
|
||||
voiceFontEntry(LLUUID& id);
|
||||
~voiceFontEntry();
|
||||
|
||||
LLUUID mID;
|
||||
S32 mFontIndex;
|
||||
std::string mName;
|
||||
LLDate mExpirationDate;
|
||||
S32 mFontType;
|
||||
S32 mFontStatus;
|
||||
bool mIsNew;
|
||||
|
||||
LLFrameTimer mExpiryTimer;
|
||||
LLFrameTimer mExpiryWarningTimer;
|
||||
};
|
||||
|
||||
bool mVoiceFontsReceived;
|
||||
bool mVoiceFontsNew;
|
||||
bool mVoiceFontListDirty;
|
||||
voice_effect_list_t mVoiceFontList;
|
||||
voice_effect_list_t mVoiceFontTemplateList;
|
||||
|
||||
typedef std::map<const LLUUID, voiceFontEntry*> voice_font_map_t;
|
||||
voice_font_map_t mVoiceFontMap;
|
||||
voice_font_map_t mVoiceFontTemplateMap;
|
||||
|
||||
typedef std::set<LLVoiceEffectObserver*> voice_font_observer_set_t;
|
||||
voice_font_observer_set_t mVoiceFontObservers;
|
||||
|
||||
LLFrameTimer mVoiceFontExpiryTimer;
|
||||
|
||||
|
||||
// Audio capture buffer
|
||||
|
||||
void captureBufferRecordStartSendMessage();
|
||||
void captureBufferRecordStopSendMessage();
|
||||
void captureBufferPlayStartSendMessage(const LLUUID& voice_font_id = LLUUID::null);
|
||||
void captureBufferPlayStopSendMessage();
|
||||
|
||||
bool mCaptureBufferMode; // Disconnected from voice channels while using the capture buffer.
|
||||
bool mCaptureBufferRecording; // A voice sample is being captured.
|
||||
bool mCaptureBufferRecorded; // A voice sample is captured in the buffer ready to play.
|
||||
bool mCaptureBufferPlaying; // A voice sample is being played.
|
||||
|
||||
LLTimer mCaptureTimer;
|
||||
LLUUID mPreviewVoiceFont;
|
||||
LLUUID mPreviewVoiceFontLast;
|
||||
S32 mPlayRequestCount;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -890,7 +1022,13 @@ protected:
|
|||
int numberOfAliases;
|
||||
std::string subscriptionHandle;
|
||||
std::string subscriptionType;
|
||||
|
||||
S32 id;
|
||||
std::string descriptionString;
|
||||
LLDate expirationDate;
|
||||
bool hasExpired;
|
||||
S32 fontType;
|
||||
S32 fontStatus;
|
||||
std::string mediaCompletionType;
|
||||
|
||||
// Members for processing text between tags
|
||||
std::string textBuffer;
|
||||
|
|
@ -907,11 +1045,9 @@ protected:
|
|||
void StartTag(const char *tag, const char **attr);
|
||||
void EndTag(const char *tag);
|
||||
void CharData(const char *buffer, int length);
|
||||
|
||||
LLDate expiryTimeStampToLLDate(const std::string& vivox_ts);
|
||||
};
|
||||
|
||||
|
||||
#endif //LL_VIVOX_VOICE_CLIENT_H
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
can_resize="true"
|
||||
can_minimize="true"
|
||||
can_close="false"
|
||||
height="202"
|
||||
height="205"
|
||||
layout="topleft"
|
||||
min_height="124"
|
||||
min_width="190"
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
user_resize="false"
|
||||
auto_resize="false"
|
||||
layout="topleft"
|
||||
height="26"
|
||||
height="20"
|
||||
name="my_panel">
|
||||
<avatar_icon
|
||||
enabled="false"
|
||||
|
|
@ -86,23 +86,38 @@
|
|||
visible="true"
|
||||
width="20" />
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
user_resize="false"
|
||||
follows="top|left"
|
||||
height="26"
|
||||
visible="true"
|
||||
layout="topleft"
|
||||
name="leave_call_btn_panel"
|
||||
width="100">
|
||||
<button
|
||||
follows="right|top"
|
||||
height="23"
|
||||
top_pad="0"
|
||||
label="Leave Call"
|
||||
name="leave_call_btn"
|
||||
width="100" />
|
||||
</layout_panel>
|
||||
<layout_stack
|
||||
clip="true"
|
||||
auto_resize="false"
|
||||
follows="left|top|right"
|
||||
height="26"
|
||||
layout="topleft"
|
||||
mouse_opaque="false"
|
||||
name="voice_effect_and_leave_call_stack"
|
||||
orientation="horizontal"
|
||||
width="262">
|
||||
<panel
|
||||
class="panel_voice_effect"
|
||||
name="panel_voice_effect"
|
||||
visiblity_control="VoiceMorphingEnabled"
|
||||
filename="panel_voice_effect.xml" />
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
user_resize="false"
|
||||
follows="top|right"
|
||||
height="23"
|
||||
visible="true"
|
||||
layout="topleft"
|
||||
name="leave_call_btn_panel"
|
||||
width="100">
|
||||
<button
|
||||
follows="right|top"
|
||||
height="23"
|
||||
label="Leave Call"
|
||||
name="leave_call_btn"
|
||||
width="100" />
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
<layout_panel
|
||||
follows="all"
|
||||
layout="topleft"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
legacy_header_height="18"
|
||||
can_resize="true"
|
||||
height="420"
|
||||
name="voice_effects"
|
||||
help_topic="voice_effects"
|
||||
title="PREVIEW VOICE MORPHING"
|
||||
background_visible="true"
|
||||
follows="all"
|
||||
label="Places"
|
||||
layout="topleft"
|
||||
min_height="350"
|
||||
min_width="330"
|
||||
width="455">
|
||||
<string name="no_voice_effect">
|
||||
(No Voice Morph)
|
||||
</string>
|
||||
<string name="active_voice_effect">
|
||||
(Active)
|
||||
</string>
|
||||
<string name="unsubscribed_voice_effect">
|
||||
(Unsubscribed)
|
||||
</string>
|
||||
<string name="new_voice_effect">
|
||||
(New!)
|
||||
</string>
|
||||
<text
|
||||
height="68"
|
||||
word_wrap="true"
|
||||
use_ellipses="true"
|
||||
type="string"
|
||||
follows="left|top|right"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
name="status_text"
|
||||
right="-10"
|
||||
top="25">
|
||||
To preview any of the Voice Morphing effects, click the Record button to record a short snippet of voice, then click any Voice Morph in the list to hear how it will sound.
|
||||
|
||||
To reconnect to Nearby Voice simply close this window.
|
||||
</text>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="23"
|
||||
label="Record Sample"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
name="record_btn"
|
||||
tool_tip="Record a sample of your voice."
|
||||
top_pad="5"
|
||||
width="150">
|
||||
<button.commit_callback
|
||||
function="VoiceEffect.Record" />
|
||||
</button>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="23"
|
||||
label="Stop"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="record_stop_btn"
|
||||
top_delta="0"
|
||||
width="150">
|
||||
<button.commit_callback
|
||||
function="VoiceEffect.Stop" />
|
||||
</button>
|
||||
<text
|
||||
height="18"
|
||||
halign="right"
|
||||
use_ellipses="true"
|
||||
type="string"
|
||||
follows="left|top|right"
|
||||
layout="topleft"
|
||||
left_pad="10"
|
||||
name="voice_morphing_link"
|
||||
right="-10"
|
||||
top_delta="5">
|
||||
[[URL] Get Voice Morphing]
|
||||
</text>
|
||||
<scroll_list
|
||||
bottom="-10"
|
||||
draw_heading="true"
|
||||
follows="all"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
multi_select="false"
|
||||
name="voice_effect_list"
|
||||
right="-10"
|
||||
tool_tip="Record a sample of your voice, then click an effect to preview."
|
||||
top="128">
|
||||
<scroll_list.columns
|
||||
label="Voice Morph"
|
||||
name="name" relative_width="0.41"/>
|
||||
<scroll_list.columns
|
||||
dynamic_width="true"
|
||||
label="Expires"
|
||||
name="expires"
|
||||
relative_width="0.59" />
|
||||
</scroll_list>
|
||||
</floater>
|
||||
|
|
@ -80,6 +80,17 @@
|
|||
function="Floater.Toggle"
|
||||
parameter="gestures" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="My Voice"
|
||||
name="ShowVoice"
|
||||
visibility_control="VoiceMorphingEnabled">
|
||||
<menu_item_check.on_check
|
||||
function="Floater.Visible"
|
||||
parameter="voice_effect" />
|
||||
<menu_item_check.on_click
|
||||
function="Floater.Toggle"
|
||||
parameter="voice_effect" />
|
||||
</menu_item_check>
|
||||
<menu
|
||||
label="My Status"
|
||||
name="Status"
|
||||
|
|
|
|||
|
|
@ -5956,6 +5956,50 @@ We are creating a voice channel for you. This may take up to one minute.
|
|||
<unique/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notify.tga"
|
||||
name="VoiceEffectsExpired"
|
||||
sound="UISndAlert"
|
||||
persist="true"
|
||||
type="notify">
|
||||
One or more of your subscribed Voice Morphs has expired.
|
||||
[[URL] Click here] to renew your subscription.
|
||||
<unique/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notify.tga"
|
||||
name="VoiceEffectsExpiredInUse"
|
||||
sound="UISndAlert"
|
||||
persist="true"
|
||||
type="notify">
|
||||
The active Voice Morph has expired, your normal voice settings have been applied.
|
||||
[[URL] Click here] to renew your subscription.
|
||||
<unique/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notify.tga"
|
||||
name="VoiceEffectsWillExpire"
|
||||
sound="UISndAlert"
|
||||
persist="true"
|
||||
type="notify">
|
||||
One or more of your Voice Morphs will expire in less than [INTERVAL] days.
|
||||
[[URL] Click here] to renew your subscription.
|
||||
<unique/>
|
||||
</notification>
|
||||
LLNotificationsUtil::add("VoiceEffectsNew");
|
||||
|
||||
<notification
|
||||
icon="notify.tga"
|
||||
name="VoiceEffectsNew"
|
||||
sound="UISndAlert"
|
||||
persist="true"
|
||||
type="notify">
|
||||
New Voice Morphs are available!
|
||||
<unique/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notifytip.tga"
|
||||
name="Cannot enter parcel: not a group member"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<panel
|
||||
follows="all"
|
||||
height="26"
|
||||
layout="topleft"
|
||||
name="panel_voice_effect"
|
||||
width="200">
|
||||
<string name="no_voice_effect">
|
||||
No Voice Morph
|
||||
</string>
|
||||
<string name="preview_voice_effects">
|
||||
Preview Voice Morphing ▶
|
||||
</string>
|
||||
<string name="get_voice_effects">
|
||||
Get Voice Morphing ▶
|
||||
</string>
|
||||
<combo_box
|
||||
enabled="false"
|
||||
follows="left|top|right"
|
||||
height="23"
|
||||
name="voice_effect"
|
||||
tool_tip="Select a Voice Morphing effect to change your voice."
|
||||
top_pad="0"
|
||||
width="200">
|
||||
<combo_box.item
|
||||
label="No Voice Morph"
|
||||
name="no_voice_effect"
|
||||
top_pad="0"
|
||||
value="0" />
|
||||
<combo_box.commit_callback
|
||||
function="Voice.CommitVoiceEffect" />
|
||||
</combo_box>
|
||||
</panel>
|
||||
|
|
@ -3086,10 +3086,12 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
|
|||
<string name="unread_chat_multiple">
|
||||
[SOURCES] have said something new
|
||||
</string>"
|
||||
<string name="session_initialization_timed_out_error">
|
||||
The session initialization is timed out
|
||||
</string>
|
||||
|
||||
<string name="session_initialization_timed_out_error">
|
||||
The session initialization is timed out
|
||||
</string>
|
||||
|
||||
<string name="voice_morphing_url">http://secondlife.com/landing/v0icem0rphingt3st</string>
|
||||
|
||||
<!-- Financial operations strings -->
|
||||
<string name="paid_you_ldollars">[NAME] paid you L$[AMOUNT]</string>
|
||||
<string name="you_paid_ldollars">You paid [NAME] L$[AMOUNT] [REASON].</string>
|
||||
|
|
|
|||
Loading…
Reference in New Issue