EXT-7138 FIXED Merge Voice Morphing from aimee/viewer-trunk_voice-features

master
Aimee Linden 2010-05-28 13:18:50 +01:00
commit 176b5c5a67
25 changed files with 2161 additions and 135 deletions

View File

@ -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

View File

@ -41,6 +41,8 @@
</array>
<key>tags</key>
<array>
<!-- sample entry for debugging a specific item -->
<!-- <string>Voice</string> -->
</array>
</map>
</array>

View File

@ -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>

View File

@ -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

View File

@ -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();

View File

@ -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; }

View File

@ -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());
// }
//}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -94,7 +94,7 @@ public:
mAvalineCallers.insert(avaline_caller_id);
}
void onChange()
void onParticipantsChanged()
{
uuid_set_t participant_uuids;
LLVoiceClient::getInstance()->getParticipantList(participant_uuids);

View File

@ -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;

View File

@ -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>);

View File

@ -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));
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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>

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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>