summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoxie Linden <roxie@lindenlab.com>2026-05-12 14:22:47 -0700
committerRoxie Linden <roxie@lindenlab.com>2026-05-12 14:22:47 -0700
commit186320e448459e57bb13c06d2605504a5ad695e6 (patch)
treed2408c112a7ad61d2773d0f62f47b59a0a9947b0
parent28f86aed5394345396689ac1b04a4b49c668bcba (diff)
Remove Vivox-related code
Remove the Vivox-related code altogether, including SLVoice.
-rw-r--r--autobuild.xml58
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake60
-rw-r--r--indra/cmake/ViewerMiscLibs.cmake2
-rw-r--r--indra/newview/CMakeLists.txt16
-rw-r--r--indra/newview/app_settings/settings.xml170
-rw-r--r--indra/newview/installers/windows/installer_template.nsi3
-rw-r--r--indra/newview/llappviewer.cpp1
-rw-r--r--indra/newview/llimview.cpp12
-rw-r--r--indra/newview/llspeakers.cpp2
-rw-r--r--indra/newview/llviewermenu.cpp1
-rw-r--r--indra/newview/llviewerstats.cpp3
-rw-r--r--indra/newview/llvoiceclient.cpp102
-rw-r--r--indra/newview/llvoiceclient.h11
-rw-r--r--indra/newview/llvoicevivox.cpp7926
-rw-r--r--indra/newview/llvoicevivox.h1093
-rw-r--r--indra/newview/llvoicewebrtc.cpp6
-rw-r--r--indra/newview/llvoicewebrtc.h1
-rwxr-xr-xindra/newview/viewer_manifest.py28
18 files changed, 24 insertions, 9471 deletions
diff --git a/autobuild.xml b/autobuild.xml
index 9945672bd2..1e315b68e5 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -2192,64 +2192,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>description</key>
<string>Generated headers and sources for OpenXR loader.</string>
</map>
- <key>slvoice</key>
- <map>
- <key>platforms</key>
- <map>
- <key>darwin64</key>
- <map>
- <key>archive</key>
- <map>
- <key>hash</key>
- <string>1e70b06fe6eb9796097010871b32d8e95167e373</string>
- <key>hash_algorithm</key>
- <string>sha1</string>
- <key>url</key>
- <string>https://automated-builds-secondlife-com.s3.amazonaws.com/gh/secondlife/3p-slvoice/slvoice-4.10.0000.32327.5fc3fe7c.5942f08-darwin64-5942f08.tar.zst</string>
- </map>
- <key>name</key>
- <string>darwin64</string>
- </map>
- <key>linux64</key>
- <map>
- <key>archive</key>
- <map>
- <key>hash</key>
- <string>92b0ae08832bd0e99c34ef8f3e6346ad</string>
- <key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/613/1289/slvoice-3.2.0002.10426.500605-linux64-500605.tar.bz2</string>
- </map>
- <key>name</key>
- <string>linux64</string>
- </map>
- <key>windows64</key>
- <map>
- <key>archive</key>
- <map>
- <key>hash</key>
- <string>ddfb7c30d9756915e8b26f44e2ee3a69ee87fb9a</string>
- <key>hash_algorithm</key>
- <string>sha1</string>
- <key>url</key>
- <string>https://automated-builds-secondlife-com.s3.amazonaws.com/gh/secondlife/3p-slvoice/slvoice-4.10.0000.32327.5fc3fe7c.5942f08-windows64-5942f08.tar.zst</string>
- </map>
- <key>name</key>
- <string>windows64</string>
- </map>
- </map>
- <key>license</key>
- <string>Mixed</string>
- <key>license_file</key>
- <string>LICENSES/vivox_licenses.txt</string>
- <key>copyright</key>
- <string>2010 Vivox, including audio coding using Polycom¨ Siren14TM (ITU-T Rec. G.722.1 Annex C)</string>
- <key>version</key>
- <string>4.10.0000.32327.5fc3fe7c.5942f08</string>
- <key>name</key>
- <string>slvoice</string>
- <key>description</key>
- <string>Vivox SDK components</string>
- </map>
<key>sse2neon</key>
<map>
<key>platforms</key>
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 680f2f3ac2..667a04a1c5 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -29,29 +29,6 @@ endmacro()
###################################################################
if(WINDOWS)
#*******************************
- # VIVOX - *NOTE: no debug version
- set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
-
- # ND, it seems there is no such thing defined. At least when building a viewer
- # Does this maybe matter on some LL buildserver? Otherwise this and the snippet using slvoice_src_dir
- # can all go
- if( ARCH_PREBUILT_BIN_RELEASE )
- set(slvoice_src_dir "${ARCH_PREBUILT_BIN_RELEASE}")
- endif()
- set(slvoice_files SLVoice.exe )
- if (ADDRESS_SIZE EQUAL 64)
- list(APPEND vivox_libs
- vivoxsdk_x64.dll
- ortp_x64.dll
- )
- else (ADDRESS_SIZE EQUAL 64)
- list(APPEND vivox_libs
- vivoxsdk.dll
- ortp.dll
- )
- endif (ADDRESS_SIZE EQUAL 64)
-
- #*******************************
# Misc shared libs
set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
@@ -159,12 +136,6 @@ if(WINDOWS)
endforeach()
elseif(DARWIN)
- set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
- set(slvoice_files SLVoice)
- set(vivox_libs
- libortp.dylib
- libvivoxsdk.dylib
- )
set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
set(debug_files
)
@@ -188,15 +159,6 @@ elseif(LINUX)
set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}")
set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}")
- set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
- set(vivox_libs
- libsndfile.so.1
- libortp.so
- libvivoxoal.so.1
- libvivoxsdk.so
- )
- set(slvoice_files SLVoice)
-
# *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
# or ARCH_PREBUILT_DIRS
set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}")
@@ -226,8 +188,6 @@ elseif(LINUX)
else(WINDOWS)
message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...")
- set(vivox_lib_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux")
- set(vivox_libs "")
# *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
# or ARCH_PREBUILT_DIRS
set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib/debug")
@@ -249,26 +209,6 @@ endif(WINDOWS)
# Done building the file lists, now set up the copy commands.
################################################################
-# Curiously, slvoice_files are only copied to SHARED_LIB_STAGING_DIR_RELEASE.
-# It's unclear whether this is oversight or intentional, but anyway leave the
-# single copy_if_different command rather than using to_staging_dirs.
-
-if( slvoice_src_dir )
- copy_if_different(
- ${slvoice_src_dir}
- "${SHARED_LIB_STAGING_DIR_RELEASE}"
- out_targets
- ${slvoice_files}
- )
- list(APPEND third_party_targets ${out_targets})
-endif()
-
-to_staging_dirs(
- ${vivox_lib_dir}
- third_party_targets
- ${vivox_libs}
- )
-
to_staging_dirs(
${release_src_dir}
third_party_targets
diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake
index cae68fbc11..f91222aa75 100644
--- a/indra/cmake/ViewerMiscLibs.cmake
+++ b/indra/cmake/ViewerMiscLibs.cmake
@@ -16,8 +16,6 @@ if( NOT USE_CONAN )
use_prebuilt_binary(libhunspell)
endif()
-use_prebuilt_binary(slvoice)
-
use_prebuilt_binary(nanosvg)
use_prebuilt_binary(viewer-fonts)
use_prebuilt_binary(emoji_shortcodes)
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1d1553355e..861712fb58 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -723,7 +723,6 @@ set(viewer_SOURCE_FILES
llvoicechannel.cpp
llvoiceclient.cpp
llvoicevisualizer.cpp
- llvoicevivox.cpp
llvoicewebrtc.cpp
llvoinventorylistener.cpp
llvopartgroup.cpp
@@ -1396,7 +1395,6 @@ set(viewer_HEADER_FILES
llvoicechannel.h
llvoiceclient.h
llvoicevisualizer.h
- llvoicevivox.h
llvoicewebrtc.h
llvoinventorylistener.h
llvopartgroup.h
@@ -1785,9 +1783,7 @@ if (WINDOWS)
${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
${SHARED_LIB_STAGING_DIR}/openjp2.dll
${SHARED_LIB_STAGING_DIR}/llwebrtc.dll
- #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/SLVoice.exe
#${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/libsndfile-1.dll
- #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/vivoxoal.dll
${AUTOBUILD_INSTALL_DIR}/ca-bundle.crt
${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt
${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt
@@ -1798,18 +1794,6 @@ if (WINDOWS)
media_plugin_example
)
- if (ADDRESS_SIZE EQUAL 64)
- list(APPEND COPY_INPUT_DEPENDENCIES
- ${SHARED_LIB_STAGING_DIR}/vivoxsdk_x64.dll
- ${SHARED_LIB_STAGING_DIR}/ortp_x64.dll
- )
- else (ADDRESS_SIZE EQUAL 64)
- list(APPEND COPY_INPUT_DEPENDENCIES
- ${SHARED_LIB_STAGING_DIR}/vivoxsdk.dll
- ${SHARED_LIB_STAGING_DIR}/ortp.dll
- )
- endif (ADDRESS_SIZE EQUAL 64)
-
if (TARGET ll::discord_sdk)
list(APPEND COPY_INPUT_DEPENDENCIES
${SHARED_LIB_STAGING_DIR}/discord_partner_sdk.dll
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index d7026d2dce..c41a1e5b88 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -13498,141 +13498,8 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>VivoxAutoPostCrashDumps</key>
- <map>
- <key>Comment</key>
- <string>If true, SLVoice will automatically send crash dumps directly to Vivox.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>VivoxDebugLevel</key>
- <map>
- <key>Comment</key>
- <string>Logging level to use when launching the vivox daemon</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>0</string>
- </map>
- <key>VivoxLogDirectory</key>
- <map>
- <key>Comment</key>
- <string>Default log path is Application Support/SecondLife/logs specify alternate absolute path here.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VivoxShutdownTimeout</key>
- <map>
- <key>Comment</key>
- <string>shutdown timeout in miliseconds. The amount of time to wait for the service to shutdown gracefully after the last disconnect</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5</string>
- </map>
- <key>VivoxDebugSIPURIHostName</key>
- <map>
- <key>Comment</key>
- <string>Hostname portion of vivox SIP URIs (empty string for the default).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VivoxDebugVoiceAccountServerURI</key>
- <map>
- <key>Comment</key>
- <string>URI to the vivox account management server (empty string for the default).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VivoxVoiceHost</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice host to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>127.0.0.1</string>
- </map>
- <key>VivoxVoicePort</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice port to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>44125</integer>
- </map>
-
- <key>VivoxVadAuto</key>
- <map>
- <key>Comment</key>
- <string>A flag indicating if the automatic VAD is enabled (1) or disabled (0). The individual settings are ignored if the auto-mode is enabled</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VivoxVadHangover</key>
- <map>
- <key>Comment</key>
- <string>The time (in milliseconds) that it takes or the VAD to switch back to silence from speech mode after the last speech frame has been detected</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>2000</integer>
- </map>
- <key>VivoxVadNoiseFloor</key>
- <map>
- <key>Comment</key>
- <string>A dimensionless value between 0 and 20000 (default 576) that controls the maximum level at which the noise floor may be set at by the VAD's noise tracking</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>576</integer>
- </map>
- <key>VivoxVadSensitivity</key>
- <map>
- <key>Comment</key>
- <string>A dimensionless value between 0 and 100, indicating the 'sensitivity of the VAD'. Increasing this value corresponds to decreasing the sensitivity of the VAD and 0 is turned off altogether</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VoiceCallsFriendsOnly</key>
- <!-- deprecated (see SL-12871) -->
+ <key>VoiceCallsFriendsOnly</key>
+ <!-- deprecated (see SL-12871) -->
<map>
<key>Comment</key>
<string>(Deprecated) Only accept voice calls from residents on your friends list</string>
@@ -13709,17 +13576,6 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>VoiceHost</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice host to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>127.0.0.1</string>
- </map>
<key>VoiceImageLevel0</key>
<map>
<key>Comment</key>
@@ -13808,17 +13664,6 @@
<key>Value</key>
<string>Default</string>
</map>
- <key>VoiceLogFile</key>
- <map>
- <key>Comment</key>
- <string>Log file to use when launching the voice daemon</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
<key>VoiceOutputAudioDevice</key>
<map>
<key>Comment</key>
@@ -13841,17 +13686,6 @@
<key>Value</key>
<integer>10</integer>
</map>
- <key>VoicePort</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice port to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>44125</integer>
- </map>
<key>VoiceEchoCancellation</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 07ed0d0824..cf12be91c3 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -865,9 +865,6 @@ Delete "$INSTDIR\trial\*.html"
Delete "$INSTDIR\newview.exe"
Delete "$INSTDIR\SecondLife.exe"
-# MAINT-3099 workaround - prevent these log files, if present, from causing a user alert
-Delete "$INSTDIR\VivoxVoiceService-*.log"
-
# Remove entire help directory
RMDir /r "$INSTDIR\help"
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 46e64c2a4e..59b8ff5c70 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2983,7 +2983,6 @@ bool LLAppViewer::initConfiguration()
{
// This is the second instance of SL. Mute voice,
// but make sure the setting is *not* persisted.
- // Also see LLVivoxVoiceClient::voiceEnabled()
LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat");
if (enable_voice)
{
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index ad01e11d48..252eb32e7c 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -89,8 +89,7 @@ const S32 XL8_PADDING = 3; // XL8_START_TAG.size() + XL8_END_TAG.size()
const static U32 SESSION_INITIALIZATION_TIMEOUT = 30;
// This enum corresponds to the sim's and adds P2P_CHAT_SESSION,
-// as webrtc uses the multiagent chat mechanism for p2p calls,
-// instead of relying on vivox calling.
+// as webrtc uses the multiagent chat mechanism for p2p calls.
// Don't change this without consulting a server developer.
enum EMultiAgentChatSessionType
{
@@ -1943,12 +1942,6 @@ void LLIMModel::sendMessage(const std::string& utf8_text,
info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id);
U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE;
- // Old call to send messages to SLim client, no longer supported.
- //if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id)))
- //{
- // // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice.
- // sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text);
- //}
if(!sent)
{
@@ -3088,8 +3081,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload
{
if (type == IM_SESSION_P2P_INVITE)
{
- // decline p2p voice, either via the vivox-style call mechanism
- // or via the webrtc-style "decline p2p" mechanism.
+ // decline p2p voice, via the webrtc-style "decline p2p" mechanism.
LLVoiceP2PIncomingCallInterfacePtr call = LLVoiceClient::getInstance()->getIncomingCallInterface(payload["voice_channel_info"]);
if (call)
{
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index f079c70c6c..c75314825c 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -438,7 +438,7 @@ void LLSpeakerMgr::update(bool resort_ok)
{
if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL)
{
- // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice)
+ // external speakers should be timed out when they leave the voice channel
speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
}
else
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index dbcf4fbbf4..5a79aa91bf 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -127,7 +127,6 @@
#include "llviewerstatsrecorder.h"
#include "llvlcomposition.h"
#include "llvoavatarself.h"
-#include "llvoicevivox.h"
#include "llworld.h"
#include "llworldmap.h"
#include "pipeline.h"
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 5193514fe8..4dcd1cc03a 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -62,7 +62,6 @@
#include "llsdserialize.h"
#include "llsdutil.h"
#include "llcorehttputil.h"
-#include "llvoicevivox.h"
#include "llinventorymodel.h"
#include "lluiusage.h"
#include "lltranslate.h"
@@ -796,8 +795,6 @@ void send_viewer_stats(bool include_preferences)
body["ui"] = LLUIUsage::instance().asLLSD();
- body["stats"]["voice"] = LLVoiceVivoxStats::getInstance()->read();
-
// Misc stats, two strings and two ints
// These are not expecticed to persist across multiple releases
// Comment any changes with your name and the expected release revision
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 71a9e71a9f..51a7204782 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -25,7 +25,6 @@
*/
#include "llvoiceclient.h"
-#include "llvoicevivox.h"
#include "llvoicewebrtc.h"
#include "llviewernetwork.h"
#include "llviewercontrol.h"
@@ -116,11 +115,7 @@ std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserv
LLVoiceModuleInterface *getVoiceModule(const std::string &voice_server_type)
{
- if (voice_server_type == VIVOX_VOICE_SERVER_TYPE || voice_server_type.empty())
- {
- return (LLVoiceModuleInterface *) LLVivoxVoiceClient::getInstance();
- }
- else if (voice_server_type == WEBRTC_VOICE_SERVER_TYPE)
+ if (voice_server_type == WEBRTC_VOICE_SERVER_TYPE)
{
return (LLVoiceModuleInterface *) LLWebRTCVoiceClient::getInstance();
}
@@ -166,7 +161,6 @@ void LLVoiceClient::init(LLPumpIO *pump)
// Initialize all of the voice modules
m_servicePump = pump;
LLWebRTCVoiceClient::getInstance()->init(pump);
- LLVivoxVoiceClient::getInstance()->init(pump);
}
void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
@@ -177,7 +171,6 @@ void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &age
}
mRegionChangedCallbackSlot = gAgent.addRegionChangedCallback(boost::bind(&LLVoiceClient::onRegionChanged, this));
LLWebRTCVoiceClient::getInstance()->userAuthorized(user_id, agentID);
- LLVivoxVoiceClient::getInstance()->userAuthorized(user_id, agentID);
}
void LLVoiceClient::handleSimulatorFeaturesReceived(const LLSD &simulatorFeatures)
@@ -185,7 +178,7 @@ void LLVoiceClient::handleSimulatorFeaturesReceived(const LLSD &simulatorFeature
std::string voiceServerType = simulatorFeatures["VoiceServerType"].asString();
if (voiceServerType.empty())
{
- voiceServerType = VIVOX_VOICE_SERVER_TYPE;
+ voiceServerType = WEBRTC_VOICE_SERVER_TYPE;
}
if (mSpatialVoiceModule && !mNonSpatialVoiceModule)
@@ -287,19 +280,14 @@ void LLVoiceClient::setHidden(bool hidden)
{
LL_INFOS("Voice") << "( " << (hidden ? "true" : "false") << " )" << LL_ENDL;
LLWebRTCVoiceClient::getInstance()->setHidden(hidden);
- LLVivoxVoiceClient::getInstance()->setHidden(hidden);
}
void LLVoiceClient::terminate()
{
- if (LLVivoxVoiceClient::instanceExists())
+ if (LLWebRTCVoiceClient::instanceExists())
{
LLWebRTCVoiceClient::getInstance()->terminate();
}
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->terminate();
- }
mSpatialVoiceModule = NULL;
m_servicePump = NULL;
@@ -335,7 +323,6 @@ void LLVoiceClient::updateSettings()
updateMicMuteLogic();
LLWebRTCVoiceClient::getInstance()->updateSettings();
- LLVivoxVoiceClient::getInstance()->updateSettings();
}
//--------------------------------------------------
@@ -344,13 +331,11 @@ void LLVoiceClient::updateSettings()
void LLVoiceClient::tuningStart()
{
LLWebRTCVoiceClient::getInstance()->tuningStart();
- LLVivoxVoiceClient::getInstance()->tuningStart();
}
void LLVoiceClient::tuningStop()
{
LLWebRTCVoiceClient::getInstance()->tuningStop();
- LLVivoxVoiceClient::getInstance()->tuningStop();
}
bool LLVoiceClient::inTuningMode()
@@ -393,13 +378,11 @@ void LLVoiceClient::refreshDeviceLists(bool clearCurrentList)
void LLVoiceClient::setCaptureDevice(const std::string& name)
{
- LLVivoxVoiceClient::getInstance()->setCaptureDevice(name);
LLWebRTCVoiceClient::getInstance()->setCaptureDevice(name);
}
void LLVoiceClient::setRenderDevice(const std::string& name)
{
- LLVivoxVoiceClient::getInstance()->setRenderDevice(name);
LLWebRTCVoiceClient::getInstance()->setRenderDevice(name);
}
@@ -421,13 +404,11 @@ const LLVoiceDeviceList& LLVoiceClient::getRenderDevices()
void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants) const
{
LLWebRTCVoiceClient::getInstance()->getParticipantList(participants);
- LLVivoxVoiceClient::getInstance()->getParticipantList(participants);
}
bool LLVoiceClient::isParticipant(const LLUUID &speaker_id) const
{
- return LLWebRTCVoiceClient::getInstance()->isParticipant(speaker_id) ||
- LLVivoxVoiceClient::getInstance()->isParticipant(speaker_id);
+ return LLWebRTCVoiceClient::getInstance()->isParticipant(speaker_id);
}
@@ -519,14 +500,12 @@ void LLVoiceClient::activateSpatialChannel(bool activate)
bool LLVoiceClient::isCurrentChannel(const LLSD& channelInfo)
{
- return LLWebRTCVoiceClient::getInstance()->isCurrentChannel(channelInfo) ||
- LLVivoxVoiceClient::getInstance()->isCurrentChannel(channelInfo);
+ return LLWebRTCVoiceClient::getInstance()->isCurrentChannel(channelInfo);
}
bool LLVoiceClient::compareChannels(const LLSD &channelInfo1, const LLSD &channelInfo2)
{
- return LLWebRTCVoiceClient::getInstance()->compareChannels(channelInfo1, channelInfo2) ||
- LLVivoxVoiceClient::getInstance()->compareChannels(channelInfo1, channelInfo2);
+ return LLWebRTCVoiceClient::getInstance()->compareChannels(channelInfo1, channelInfo2);
}
LLVoiceP2PIncomingCallInterfacePtr LLVoiceClient::getIncomingCallInterface(const LLSD& voice_call_info)
@@ -554,8 +533,8 @@ LLVoiceP2POutgoingCallInterface *LLVoiceClient::getOutgoingCallInterface(const L
if (voiceChannelInfo.has("voice_server_type") && voiceChannelInfo["voice_server_type"] != voice_server_type)
{
// there's a mismatch between what the peer is offering and what our server
- // can handle, so downgrade to vivox
- voice_server_type = VIVOX_VOICE_SERVER_TYPE;
+ // can handle, so default to webrtc
+ voice_server_type = WEBRTC_VOICE_SERVER_TYPE;
}
LLVoiceModuleInterface *module = getVoiceModule(voice_server_type);
return dynamic_cast<LLVoiceP2POutgoingCallInterface *>(module);
@@ -568,13 +547,11 @@ LLVoiceP2POutgoingCallInterface *LLVoiceClient::getOutgoingCallInterface(const L
void LLVoiceClient::setVoiceVolume(F32 volume)
{
LLWebRTCVoiceClient::getInstance()->setVoiceVolume(volume);
- LLVivoxVoiceClient::getInstance()->setVoiceVolume(volume);
}
void LLVoiceClient::setMicGain(F32 gain)
{
LLWebRTCVoiceClient::getInstance()->setMicGain(gain);
- LLVivoxVoiceClient::getInstance()->setMicGain(gain);
}
@@ -624,10 +601,6 @@ void LLVoiceClient::setVoiceEnabled(bool enabled)
{
LLWebRTCVoiceClient::getInstance()->setVoiceEnabled(enabled);
}
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->setVoiceEnabled(enabled);
- }
}
void LLVoiceClient::updateMicMuteLogic()
@@ -647,7 +620,6 @@ void LLVoiceClient::updateMicMuteLogic()
new_mic_mute = true;
}
LLWebRTCVoiceClient::getInstance()->setMuteMic(new_mic_mute);
- LLVivoxVoiceClient::getInstance()->setMuteMic(new_mic_mute);
}
void LLVoiceClient::setMuteMic(bool muted)
@@ -742,17 +714,12 @@ bool LLVoiceClient::getVoiceEnabled(const LLUUID& id) const
std::string LLVoiceClient::getDisplayName(const LLUUID& id) const
{
std::string result = LLWebRTCVoiceClient::getInstance()->getDisplayName(id);
- if (result.empty())
- {
- result = LLVivoxVoiceClient::getInstance()->getDisplayName(id);
- }
return result;
}
bool LLVoiceClient::isVoiceWorking() const
{
- return LLVivoxVoiceClient::getInstance()->isVoiceWorking() ||
- LLWebRTCVoiceClient::getInstance()->isVoiceWorking();
+ return LLWebRTCVoiceClient::getInstance()->isVoiceWorking();
}
bool LLVoiceClient::isParticipantAvatar(const LLUUID& id)
@@ -767,22 +734,19 @@ bool LLVoiceClient::isOnlineSIP(const LLUUID& id)
bool LLVoiceClient::getIsSpeaking(const LLUUID& id)
{
- return LLWebRTCVoiceClient::getInstance()->getIsSpeaking(id) ||
- LLVivoxVoiceClient::getInstance()->getIsSpeaking(id);
+ return LLWebRTCVoiceClient::getInstance()->getIsSpeaking(id);
}
bool LLVoiceClient::getIsModeratorMuted(const LLUUID& id)
{
// don't bother worrying about p2p calls, as
// p2p calls don't have mute.
- return LLWebRTCVoiceClient::getInstance()->getIsModeratorMuted(id) ||
- LLVivoxVoiceClient::getInstance()->getIsModeratorMuted(id);
+ return LLWebRTCVoiceClient::getInstance()->getIsModeratorMuted(id);
}
F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
{
- return std::fmax(LLVivoxVoiceClient::getInstance()->getCurrentPower(id),
- LLWebRTCVoiceClient::getInstance()->getCurrentPower(id));
+ return LLWebRTCVoiceClient::getInstance()->getCurrentPower(id);
}
bool LLVoiceClient::getOnMuteList(const LLUUID& id)
@@ -794,13 +758,12 @@ bool LLVoiceClient::getOnMuteList(const LLUUID& id)
F32 LLVoiceClient::getUserVolume(const LLUUID& id)
{
- return std::fmax(LLVivoxVoiceClient::getInstance()->getUserVolume(id), LLWebRTCVoiceClient::getInstance()->getUserVolume(id));
+ return LLWebRTCVoiceClient::getInstance()->getUserVolume(id);
}
void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
{
LLWebRTCVoiceClient::getInstance()->setUserVolume(id, volume);
- LLVivoxVoiceClient::getInstance()->setUserVolume(id, volume);
}
//--------------------------------------------------
@@ -808,16 +771,11 @@ void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
{
- LLVivoxVoiceClient::getInstance()->addObserver(observer);
LLWebRTCVoiceClient::getInstance()->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
{
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->removeObserver(observer);
- }
if (LLWebRTCVoiceClient::instanceExists())
{
LLWebRTCVoiceClient::getInstance()->removeObserver(observer);
@@ -826,16 +784,11 @@ void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
void LLVoiceClient::addObserver(LLFriendObserver* observer)
{
- LLVivoxVoiceClient::getInstance()->addObserver(observer);
LLWebRTCVoiceClient::getInstance()->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLFriendObserver* observer)
{
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->removeObserver(observer);
- }
if (LLWebRTCVoiceClient::instanceExists())
{
LLWebRTCVoiceClient::getInstance()->removeObserver(observer);
@@ -844,38 +797,17 @@ void LLVoiceClient::removeObserver(LLFriendObserver* observer)
void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
{
- LLVivoxVoiceClient::getInstance()->addObserver(observer);
LLWebRTCVoiceClient::getInstance()->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
{
- if (LLVivoxVoiceClient::instanceExists())
- {
- LLVivoxVoiceClient::getInstance()->removeObserver(observer);
- }
if (LLWebRTCVoiceClient::instanceExists())
{
LLWebRTCVoiceClient::getInstance()->removeObserver(observer);
}
}
-std::string LLVoiceClient::sipURIFromID(const LLUUID &id) const
-{
- if (mNonSpatialVoiceModule)
- {
- return mNonSpatialVoiceModule->sipURIFromID(id);
- }
- else if (mSpatialVoiceModule)
- {
- return mSpatialVoiceModule->sipURIFromID(id);
- }
- else
- {
- return std::string();
- }
-}
-
LLSD LLVoiceClient::getP2PChannelInfoTemplate(const LLUUID& id) const
{
if (mNonSpatialVoiceModule)
@@ -908,7 +840,7 @@ class LLViewerRequiredVoiceVersion : public LLHTTPNode
const LLSD& context,
const LLSD& input) const
{
- std::string voice_server_type = "vivox";
+ std::string voice_server_type = "webrtc";
if (input.has("body") && input["body"].has("voice_server_type"))
{
voice_server_type = input["body"]["voice_server_type"].asString();
@@ -916,11 +848,7 @@ class LLViewerRequiredVoiceVersion : public LLHTTPNode
LLVoiceModuleInterface *voiceModule = NULL;
- if (voice_server_type == "vivox" || voice_server_type.empty())
- {
- voiceModule = (LLVoiceModuleInterface *) LLVivoxVoiceClient::getInstance();
- }
- else if (voice_server_type == "webrtc")
+ if (voice_server_type == "webrtc" || voice_server_type.empty())
{
voiceModule = (LLVoiceModuleInterface *) LLWebRTCVoiceClient::getInstance();
}
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 788ea3b3b3..70bce055f9 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -106,7 +106,7 @@ struct LLVoiceVersionInfo
/// @class LLVoiceP2POutgoingCallInterface
/// @brief Outgoing call interface
///
-/// For providers that support P2P signaling (vivox)
+/// For providers that support P2P signaling
/////////////////////////////////
class LLVoiceP2POutgoingCallInterface
@@ -121,7 +121,7 @@ class LLVoiceP2POutgoingCallInterface
/// @class LLVoiceP2PIncomingCallInterface
/// @brief Incoming call interface
///
-/// For providers that support P2P signaling (vivox)
+/// For providers that support P2P signaling
/////////////////////////////////
class LLVoiceP2PIncomingCallInterface
{
@@ -180,7 +180,6 @@ public:
virtual bool deviceSettingsAvailable()=0;
virtual bool deviceSettingsUpdated() = 0;
- // Requery the vivox daemon for the current list of input/output devices.
// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
// (use this if you want to know when it's done).
// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
@@ -280,7 +279,6 @@ public:
virtual void removeObserver(LLVoiceClientParticipantObserver* observer)=0;
//@}
- virtual std::string sipURIFromID(const LLUUID &id) const=0;
virtual LLSD getP2PChannelInfoTemplate(const LLUUID& id) const=0;
//@}
@@ -384,7 +382,7 @@ public:
bool deviceSettingsAvailable();
bool deviceSettingsUpdated(); // returns true when the device list has been updated recently.
- // Requery the vivox daemon for the current list of input/output devices.
+ // Requery the voice driver for the current list of input/output devices.
// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
// (use this if you want to know when it's done).
// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
@@ -488,7 +486,6 @@ public:
static void addObserver(LLVoiceClientParticipantObserver* observer);
static void removeObserver(LLVoiceClientParticipantObserver* observer);
- std::string sipURIFromID(const LLUUID &id) const;
LLSD getP2PChannelInfoTemplate(const LLUUID& id) const;
//////////////////////////
@@ -513,7 +510,7 @@ protected:
LLVoiceModuleInterface* mSpatialVoiceModule;
LLVoiceModuleInterface* mNonSpatialVoiceModule;
- LLSD mSpatialCredentials; // used to store spatial credentials for vivox
+ LLSD mSpatialCredentials; // used to store spatial credentials for the voice subsystem
// so they're available when the region voice
// server is retrieved.
LLPumpIO *m_servicePump;
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
deleted file mode 100644
index 107a08fdf8..0000000000
--- a/indra/newview/llvoicevivox.cpp
+++ /dev/null
@@ -1,7926 +0,0 @@
- /**
- * @file LLVivoxVoiceClient.cpp
- * @brief Implementation of LLVivoxVoiceClient class which is the interface to the voice client process.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include <algorithm>
-#include "llvoicevivox.h"
-
-#include "llsdutil.h"
-
-// Linden library includes
-#include "llavatarnamecache.h"
-#include "llvoavatarself.h"
-#include "llbufferstream.h"
-#include "llfile.h"
-#include "llmenugl.h"
-#ifdef LL_USESYSTEMLIBS
-# include "expat.h"
-#else
-# include "expat/expat.h"
-#endif
-#include "llcallbacklist.h"
-#include "llviewerregion.h"
-#include "llviewernetwork.h" // for gGridChoice
-#include "llbase64.h"
-#include "llviewercontrol.h"
-#include "llappviewer.h" // for gDisconnected, gDisableVoice
-#include "llprocess.h"
-
-// Viewer includes
-#include "llmutelist.h" // to check for muted avatars
-#include "llagent.h"
-#include "llcachename.h"
-#include "llimview.h" // for LLIMMgr
-#include "llparcel.h"
-#include "llviewerparcelmgr.h"
-#include "llfirstuse.h"
-#include "llspeakers.h"
-#include "lltrans.h"
-#include "llviewerwindow.h"
-#include "llviewercamera.h"
-#include "llversioninfo.h"
-
-#include "llviewernetwork.h"
-#include "llnotificationsutil.h"
-
-#include "llcorehttputil.h"
-#include "lleventfilter.h"
-
-#include "stringize.h"
-
-// for base64 decoding
-#include "apr_base64.h"
-
-#define USE_SESSION_GROUPS 0
-#define VX_NULL_POSITION -2147483648.0 /*The Silence*/
-
-extern LLMenuBarGL* gMenuBarView;
-extern void handle_voice_morphing_subscribe();
-
-const std::string VIVOX_VOICE_SERVER_TYPE = "vivox";
-
-namespace {
- const F32 VOLUME_SCALE_VIVOX = 0.01f;
-
- const F32 SPEAKING_TIMEOUT = 1.f;
-
- static const std::string VISIBLE_VOICE_SERVER_TYPE = "Vivox";
-
- // Don't retry connecting to the daemon more frequently than this:
- const F32 DAEMON_CONNECT_THROTTLE_SECONDS = 1.0f;
- const int DAEMON_CONNECT_RETRY_MAX = 3;
-
- // Don't send positional updates more frequently than this:
- const F32 UPDATE_THROTTLE_SECONDS = 0.5f;
-
- // Timeout for connection to Vivox
- const F32 CONNECT_ATTEMPT_TIMEOUT = 300.0f;
- const F32 CONNECT_DNS_TIMEOUT = 5.0f;
- const int CONNECT_RETRY_MAX = 3;
-
- const F32 LOGIN_ATTEMPT_TIMEOUT = 30.0f;
- const F32 LOGOUT_ATTEMPT_TIMEOUT = 5.0f;
- const int LOGIN_RETRY_MAX = 3;
-
- const F32 PROVISION_RETRY_TIMEOUT = 2.0;
- const int PROVISION_RETRY_MAX = 5;
-
- // Cosine of a "trivially" small angle
- const F32 FOUR_DEGREES = 4.0f * (F_PI / 180.0f);
- const F32 MINUSCULE_ANGLE_COS = (F32) cos(0.5f * FOUR_DEGREES);
-
- const F32 SESSION_JOIN_TIMEOUT = 30.0f;
-
- // Defines the maximum number of times(in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine()
- // which is treated as normal. The is the number of frames to wait for a channel join before giving up. This was changed
- // from the original count of 50 for two reason. Modern PCs have higher frame rates and sometimes the SLVoice process
- // backs up processing join requests. There is a log statement that records when channel joins take longer than 100 frames.
- const int MAX_NORMAL_JOINING_SPATIAL_NUM = 1500;
-
- // How often to check for expired voice fonts in seconds
- const F32 VOICE_FONT_EXPIRY_INTERVAL = 10.f;
- // Time of day at which Vivox expires voice font subscriptions.
- // Used to replace the time portion of received expiry timestamps.
- static const std::string VOICE_FONT_EXPIRY_TIME = "T05:00:00Z";
-
- // Maximum length of capture buffer recordings in seconds.
- const F32 CAPTURE_BUFFER_MAX_TIME = 10.f;
-
- const int ERROR_VIVOX_OBJECT_NOT_FOUND = 1001;
- const int ERROR_VIVOX_NOT_LOGGED_IN = 1007;
-}
-
-static int scale_mic_volume(float volume)
-{
- // incoming volume has the range [0.0 ... 2.0], with 1.0 as the default.
- // Map it to Vivox levels as follows: 0.0 -> 30, 1.0 -> 50, 2.0 -> 70
- return 30 + (int)(volume * 20.0f);
-}
-
-static int scale_speaker_volume(float volume)
-{
- // incoming volume has the range [0.0 ... 1.0], with 0.5 as the default.
- // Map it to Vivox levels as follows: 0.0 -> 30, 0.5 -> 50, 1.0 -> 70
- return 30 + (int)(volume * 40.0f);
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver
-{
- /* virtual */ void onChange() { LLVivoxVoiceClient::getInstance()->muteListChanged();}
-};
-
-
-void LLVoiceVivoxStats::reset()
-{
- mStartTime = -1.0f;
- mConnectCycles = 0;
- mConnectTime = -1.0f;
- mConnectAttempts = 0;
- mProvisionTime = -1.0f;
- mProvisionAttempts = 0;
- mEstablishTime = -1.0f;
- mEstablishAttempts = 0;
-}
-
-LLVoiceVivoxStats::LLVoiceVivoxStats()
-{
- reset();
-}
-
-LLVoiceVivoxStats::~LLVoiceVivoxStats()
-{
-}
-
-void LLVoiceVivoxStats::connectionAttemptStart()
-{
- if (!mConnectAttempts)
- {
- mStartTime = LLTimer::getTotalTime();
- mConnectCycles++;
- }
- mConnectAttempts++;
-}
-
-void LLVoiceVivoxStats::connectionAttemptEnd(bool success)
-{
- if ( success )
- {
- mConnectTime = (LLTimer::getTotalTime() - mStartTime) / USEC_PER_SEC;
- }
-}
-
-void LLVoiceVivoxStats::provisionAttemptStart()
-{
- if (!mProvisionAttempts)
- {
- mStartTime = LLTimer::getTotalTime();
- }
- mProvisionAttempts++;
-}
-
-void LLVoiceVivoxStats::provisionAttemptEnd(bool success)
-{
- if ( success )
- {
- mProvisionTime = (LLTimer::getTotalTime() - mStartTime) / USEC_PER_SEC;
- }
-}
-
-void LLVoiceVivoxStats::establishAttemptStart()
-{
- if (!mEstablishAttempts)
- {
- mStartTime = LLTimer::getTotalTime();
- }
- mEstablishAttempts++;
-}
-
-void LLVoiceVivoxStats::establishAttemptEnd(bool success)
-{
- if ( success )
- {
- mEstablishTime = (LLTimer::getTotalTime() - mStartTime) / USEC_PER_SEC;
- }
-}
-
-LLSD LLVoiceVivoxStats::read()
-{
- LLSD stats(LLSD::emptyMap());
-
- stats["connect_cycles"] = LLSD::Integer(mConnectCycles);
- stats["connect_attempts"] = LLSD::Integer(mConnectAttempts);
- stats["connect_time"] = LLSD::Real(mConnectTime);
-
- stats["provision_attempts"] = LLSD::Integer(mProvisionAttempts);
- stats["provision_time"] = LLSD::Real(mProvisionTime);
-
- stats["establish_attempts"] = LLSD::Integer(mEstablishAttempts);
- stats["establish_time"] = LLSD::Real(mEstablishTime);
-
- return stats;
-}
-
-static LLVivoxVoiceClientMuteListObserver mutelist_listener;
-static bool sMuteListListener_listening = false;
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-static LLProcessPtr sGatewayPtr;
-static LLEventStream sGatewayPump("VivoxDaemonPump", true);
-
-static bool isGatewayRunning()
-{
- return sGatewayPtr && sGatewayPtr->isRunning();
-}
-
-static void killGateway()
-{
- if (sGatewayPtr)
- {
- LL_DEBUGS("Voice") << "SLVoice " << sGatewayPtr->getStatusString() << LL_ENDL;
-
- sGatewayPump.stopListening("VivoxDaemonPump");
- sGatewayPtr->kill(__FUNCTION__);
- sGatewayPtr=NULL;
- }
- else
- {
- LL_DEBUGS("Voice") << "no gateway" << LL_ENDL;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-bool LLVivoxVoiceClient::sShuttingDown = false;
-bool LLVivoxVoiceClient::sConnected = false;
-LLPumpIO *LLVivoxVoiceClient::sPump = nullptr;
-
-LLVivoxVoiceClient::LLVivoxVoiceClient() :
- mWriteOffset(0),
- mHidden(true),
- mSessionTerminateRequested(false),
- mRelogRequested(false),
- mTerminateDaemon(false),
- mSpatialJoiningNum(0),
-
- mTuningMode(false),
- mTuningEnergy(0.0f),
- mTuningMicVolume(0),
- mTuningMicVolumeDirty(true),
- mTuningSpeakerVolume(50), // Set to 50 so the user can hear himself when he sets his mic volume
- mTuningSpeakerVolumeDirty(true),
- mDevicesListUpdated(false),
-
- mAudioSession(), // TBD - should be NULL
- mNextAudioSession(),
-
- mCurrentParcelLocalID(0),
- mConnectorEstablished(false),
- mAccountLoggedIn(false),
- mNumberOfAliases(0),
- mCommandCookie(0),
- mLoginRetryCount(0),
-
- mBuddyListMapPopulated(false),
- mBlockRulesListReceived(false),
- mAutoAcceptRulesListReceived(false),
-
- mCaptureDeviceDirty(false),
- mRenderDeviceDirty(false),
- mSpatialCoordsDirty(false),
- mIsInitialized(false),
-
- mMuteMic(false),
- mMuteMicDirty(false),
- mFriendsListDirty(true),
-
- mEarLocation(0),
- mSpeakerVolumeDirty(true),
- mSpeakerMuteDirty(true),
- mMicVolume(0),
- mMicVolumeDirty(true),
-
- mVoiceEnabled(false),
- mProcessChannels(false),
- mWriteInProgress(false),
-
- mVoiceFontsReceived(false),
- mVoiceFontsNew(false),
- mVoiceFontListDirty(false),
-
- mCaptureBufferMode(false),
- mCaptureBufferRecording(false),
- mCaptureBufferRecorded(false),
- mCaptureBufferPlaying(false),
- mShutdownComplete(true),
- mPlayRequestCount(0),
-
- mAvatarNameCacheConnection(),
- mIsInTuningMode(false),
- mIsInChannel(false),
- mIsJoiningSession(false),
- mIsWaitingForFonts(false),
- mIsLoggingIn(false),
- mIsLoggedIn(false),
- mIsProcessingChannels(false),
- mIsCoroutineActive(false),
- mVivoxPump("vivoxClientPump")
-{
- sShuttingDown = false;
- sConnected = false;
- sPump = nullptr;
-
- mSpeakerVolume = scale_speaker_volume(0);
-
- mVoiceVersion.serverVersion = "";
- mVoiceVersion.voiceServerType = VISIBLE_VOICE_SERVER_TYPE;
- mVoiceVersion.internalVoiceServerType = VIVOX_VOICE_SERVER_TYPE;
- mVoiceVersion.majorVersion = 1;
- mVoiceVersion.minorVersion = 0;
- mVoiceVersion.mBuildVersion = "";
- mVoiceVersion.serverVersion = "";
-
- // gMuteListp isn't set up at this point, so we defer this until later.
-// gMuteListp->addObserver(&mutelist_listener);
-
-
-#if LL_DARWIN || LL_LINUX
- // HACK: THIS DOES NOT BELONG HERE
- // When the vivox daemon dies, the next write attempt on our socket generates a SIGPIPE, which kills us.
- // This should cause us to ignore SIGPIPE and handle the error through proper channels.
- // This should really be set up elsewhere. Where should it go?
- signal(SIGPIPE, SIG_IGN);
-
- // Since we're now launching the gateway with fork/exec instead of system(), we need to deal with zombie processes.
- // Ignoring SIGCHLD should prevent zombies from being created. Alternately, we could use wait(), but I'd rather not do that.
- signal(SIGCHLD, SIG_IGN);
-#endif
-
-
- gIdleCallbacks.addFunction(idle, this);
-}
-
-//---------------------------------------------------
-
-LLVivoxVoiceClient::~LLVivoxVoiceClient()
-{
- if (mAvatarNameCacheConnection.connected())
- {
- mAvatarNameCacheConnection.disconnect();
- }
- sShuttingDown = true;
-}
-
-//---------------------------------------------------
-
-void LLVivoxVoiceClient::init(LLPumpIO *pump)
-{
- // constructor will set up LLVoiceClient::getInstance()
- sPump = pump;
-
-// LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro",
-// boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance()));
-
-}
-
-void LLVivoxVoiceClient::terminate()
-{
- if (sShuttingDown)
- {
- return;
- }
-
- // needs to be done manually here since we will not get another pass in
- // coroutines... that mechanism is long since gone.
- if (mIsLoggedIn)
- {
- logoutOfVivox(false);
- }
-
- if(sConnected)
- {
- breakVoiceConnection(false);
- sConnected = false;
- }
- else
- {
- mRelogRequested = false;
- killGateway();
- }
-
- sShuttingDown = true;
- sPump = NULL;
-}
-
-//---------------------------------------------------
-
-void LLVivoxVoiceClient::cleanUp()
-{
- LL_DEBUGS("Voice") << LL_ENDL;
-
- deleteAllSessions();
- deleteAllVoiceFonts();
- deleteVoiceFontTemplates();
- LL_DEBUGS("Voice") << "exiting" << LL_ENDL;
-}
-
-//---------------------------------------------------
-
-const LLVoiceVersionInfo& LLVivoxVoiceClient::getVersion()
-{
- return mVoiceVersion;
-}
-
-//---------------------------------------------------
-
-void LLVivoxVoiceClient::updateSettings()
-{
- setVoiceEnabled(LLVoiceClient::getInstance()->voiceEnabled());
- setEarLocation(gSavedSettings.getS32("VoiceEarLocation"));
-
- std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
- setCaptureDevice(inputDevice);
- std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
- setRenderDevice(outputDevice);
- F32 mic_level = gSavedSettings.getF32("AudioLevelMic");
- setMicGain(mic_level);
-}
-
-/////////////////////////////
-// utility functions
-
-bool LLVivoxVoiceClient::writeString(const std::string &str)
-{
- bool result = false;
- LL_DEBUGS("LowVoice") << "sending:\n" << str << LL_ENDL;
-
- if(sConnected)
- {
- apr_status_t err;
- apr_size_t size = (apr_size_t)str.size();
- apr_size_t written = size;
-
- //MARK: Turn this on to log outgoing XML
- // LL_DEBUGS("Voice") << "sending: " << str << LL_ENDL;
-
- // check return code - sockets will fail (broken, etc.)
- err = apr_socket_send(
- mSocket->getSocket(),
- (const char*)str.data(),
- &written);
-
- if(err == 0 && written == size)
- {
- // Success.
- result = true;
- }
- else if (err == 0 && written != size) {
- // Did a short write, log it for now
- LL_WARNS("Voice") << ") short write on socket sending data to vivox daemon." << "Sent " << written << "bytes instead of " << size <<LL_ENDL;
- }
- else if(APR_STATUS_IS_EAGAIN(err))
- {
- char buf[MAX_STRING];
- LL_WARNS("Voice") << "EAGAIN error " << err << " (" << apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << LL_ENDL;
- }
- else
- {
- // Assume any socket error means something bad. For now, just close the socket.
- char buf[MAX_STRING];
- LL_WARNS("Voice") << "apr error " << err << " ("<< apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << LL_ENDL;
- daemonDied();
- }
- }
-
- return result;
-}
-
-
-/////////////////////////////
-// session control messages
-void LLVivoxVoiceClient::connectorCreate()
-{
- std::ostringstream stream;
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
-
- // Transition to stateConnectorStarted when the connector handle comes back.
- std::string vivoxLogLevel = gSavedSettings.getString("VivoxDebugLevel");
- if ( vivoxLogLevel.empty() )
- {
- vivoxLogLevel = "0";
- }
- LL_DEBUGS("Voice") << "creating connector with log level " << vivoxLogLevel << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.Create.1\">"
- << "<ClientName>V2 SDK</ClientName>"
- << "<AccountManagementServer>" << mVoiceAccountServerURI << "</AccountManagementServer>"
- << "<Mode>Normal</Mode>"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Logging>"
- << "<Folder>" << logdir << "</Folder>"
- << "<FileNamePrefix>Connector</FileNamePrefix>"
- << "<FileNameSuffix>.log</FileNameSuffix>"
- << "<LogLevel>" << vivoxLogLevel << "</LogLevel>"
- << "</Logging>"
- << "<Application>" << LLVersionInfo::instance().getChannel() << " " << LLVersionInfo::instance().getVersion() << "</Application>"
- //<< "<Application></Application>" //Name can cause problems per vivox.
- << "<MaxCalls>12</MaxCalls>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::connectorShutdown()
-{
- if(mConnectorEstablished)
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.InitiateShutdown.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "</Request>"
- << "\n\n\n";
-
- mShutdownComplete = false;
- mConnectorEstablished = false;
-
- writeString(stream.str());
- }
- else
- {
- mShutdownComplete = true;
- }
-}
-
-void LLVivoxVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
-{
-
- mAccountDisplayName = user_id;
-
- LL_INFOS("Voice") << "name \"" << mAccountDisplayName << "\" , ID " << agentID << LL_ENDL;
-
- mAccountName = nameFromID(agentID);
-}
-
-void LLVivoxVoiceClient::setLoginInfo(
- const std::string& account_name,
- const std::string& password,
- const std::string& voice_sip_uri_hostname,
- const std::string& voice_account_server_uri)
-{
- mVoiceSIPURIHostName = voice_sip_uri_hostname;
- mVoiceAccountServerURI = voice_account_server_uri;
-
- if(mAccountLoggedIn)
- {
- // Already logged in.
- LL_WARNS("Voice") << "Called while already logged in." << LL_ENDL;
-
- // Don't process another login.
- return;
- }
- else if ( account_name != mAccountName )
- {
- LL_WARNS("Voice") << "Mismatched account name! " << account_name
- << " instead of " << mAccountName << LL_ENDL;
- }
- else
- {
- mAccountPassword = password;
- }
-
- std::string debugSIPURIHostName = gSavedSettings.getString("VivoxDebugSIPURIHostName");
-
- if( !debugSIPURIHostName.empty() )
- {
- LL_INFOS("Voice") << "Overriding account server based on VivoxDebugSIPURIHostName: "
- << debugSIPURIHostName << LL_ENDL;
- mVoiceSIPURIHostName = debugSIPURIHostName;
- }
-
- if( mVoiceSIPURIHostName.empty() )
- {
- // we have an empty account server name
- // so we fall back to hardcoded defaults
-
- if(LLGridManager::getInstance()->isInProductionGrid())
- {
- // Use the release account server
- mVoiceSIPURIHostName = "bhr.vivox.com";
- }
- else
- {
- // Use the development account server
- mVoiceSIPURIHostName = "bhd.vivox.com";
- }
- LL_INFOS("Voice") << "Defaulting SIP URI host: "
- << mVoiceSIPURIHostName << LL_ENDL;
-
- }
-
- std::string debugAccountServerURI = gSavedSettings.getString("VivoxDebugVoiceAccountServerURI");
-
- if( !debugAccountServerURI.empty() )
- {
- LL_INFOS("Voice") << "Overriding account server based on VivoxDebugVoiceAccountServerURI: "
- << debugAccountServerURI << LL_ENDL;
- mVoiceAccountServerURI = debugAccountServerURI;
- }
-
- if( mVoiceAccountServerURI.empty() )
- {
- // If the account server URI isn't specified, construct it from the SIP URI hostname
- mVoiceAccountServerURI = "https://www." + mVoiceSIPURIHostName + "/api2/";
- LL_INFOS("Voice") << "Inferring account server based on SIP URI Host name: "
- << mVoiceAccountServerURI << LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::idle(void* user_data)
-{
-}
-
-//=========================================================================
-// the following are methods to support the coroutine implementation of the
-// voice connection and processing. They should only be called in the context
-// of a coroutine.
-//
-//
-
-typedef enum e_voice_control_coro_state
-{
- VOICE_STATE_ERROR = -1,
- VOICE_STATE_DONE = 0,
- VOICE_STATE_TP_WAIT, // entry point
- VOICE_STATE_START_DAEMON,
- VOICE_STATE_PROVISION_ACCOUNT,
- VOICE_STATE_START_SESSION,
- VOICE_STATE_SESSION_RETRY,
- VOICE_STATE_SESSION_ESTABLISHED,
- VOICE_STATE_WAIT_FOR_CHANNEL,
- VOICE_STATE_DISCONNECT,
- VOICE_STATE_WAIT_FOR_EXIT,
-} EVoiceControlCoroState;
-
-void LLVivoxVoiceClient::voiceControlCoro()
-{
- int state = 0;
- try
- {
- // state is passed as a reference instead of being
- // a member due to unresolved issues with coroutine
- // surviving longer than LLVivoxVoiceClient
- voiceControlStateMachine(state);
- }
- catch (const LLCoros::Stop&)
- {
- LL_DEBUGS("LLVivoxVoiceClient") << "Received a shutdown exception" << LL_ENDL;
- }
- catch (const LLContinueError&)
- {
- LOG_UNHANDLED_EXCEPTION("LLVivoxVoiceClient");
- }
- catch (...)
- {
- // Ideally for Windows need to log SEH exception instead or to set SEH
- // handlers but bugsplat shows local variables for windows, which should
- // be enough
- LL_WARNS("Voice") << "voiceControlStateMachine crashed in state " << state << LL_ENDL;
- throw;
- }
-}
-
-void LLVivoxVoiceClient::voiceControlStateMachine(S32 &coro_state)
-{
- if (sShuttingDown)
- {
- return;
- }
-
- LL_DEBUGS("Voice") << "starting" << LL_ENDL;
- mIsCoroutineActive = true;
- LLCoros::set_consuming(true);
-
- U32 retry = 0;
-
- coro_state = VOICE_STATE_TP_WAIT;
-
- do
- {
- if (sShuttingDown)
- {
- // Vivox singleton performed the exit, logged out,
- // cleaned sockets, gateway and no longer cares
- // about state of coroutine, so just stop
- return;
- }
-
- switch (coro_state)
- {
- case VOICE_STATE_TP_WAIT:
- // starting point for voice
- if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
- {
- LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL;
- llcoro::suspendUntilTimeout(1.0);
- }
- else
- {
- coro_state = VOICE_STATE_START_DAEMON;
- }
- break;
-
- case VOICE_STATE_START_DAEMON:
- LL_DEBUGS("Voice") << "Launching daemon" << LL_ENDL;
- LLVoiceVivoxStats::getInstance()->reset();
- if (startAndLaunchDaemon())
- {
- coro_state = VOICE_STATE_PROVISION_ACCOUNT;
- }
- else
- {
- coro_state = VOICE_STATE_SESSION_RETRY;
- }
- break;
-
- case VOICE_STATE_PROVISION_ACCOUNT:
- if (provisionVoiceAccount())
- {
- coro_state = VOICE_STATE_START_SESSION;
- }
- else
- {
- coro_state = VOICE_STATE_SESSION_RETRY;
- }
- break;
-
- case VOICE_STATE_START_SESSION:
- if (establishVoiceConnection())
- {
- coro_state = VOICE_STATE_SESSION_ESTABLISHED;
- }
- else
- {
- coro_state = VOICE_STATE_SESSION_RETRY;
- }
- break;
-
- case VOICE_STATE_SESSION_RETRY:
- giveUp(); // cleans sockets and session
- if (mRelogRequested)
- {
- // We failed to connect, give it a bit time before retrying.
- retry++;
- F32 full_delay = llmin(5.f * (F32)retry, 60.f);
- F32 current_delay = 0.f;
- LL_INFOS("Voice") << "Voice failed to establish session after " << retry
- << " tries. Will attempt to reconnect in " << full_delay
- << " seconds" << LL_ENDL;
- while (current_delay < full_delay && !sShuttingDown)
- {
- // Assuming that a second has passed is not accurate,
- // but we don't need accurancy here, just to make sure
- // that some time passed and not to outlive voice itself
- current_delay++;
- llcoro::suspendUntilTimeout(1.f);
- }
- coro_state = VOICE_STATE_WAIT_FOR_EXIT;
- }
- else
- {
- coro_state = VOICE_STATE_DONE;
- }
- break;
-
- case VOICE_STATE_SESSION_ESTABLISHED:
- {
- // enable/disable the automatic VAD and explicitly set the initial values of
- // the VAD variables ourselves when it is off - see SL-15072 for more details
- // note: we set the other parameters too even if the auto VAD is on which is ok
- unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto");
- unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover");
- unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor");
- unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity");
- setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity);
-
- // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly
- gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
-
- if (mTuningMode)
- {
- performMicTuning();
- }
-
- coro_state = VOICE_STATE_WAIT_FOR_CHANNEL;
- }
- break;
-
- case VOICE_STATE_WAIT_FOR_CHANNEL:
- waitForChannel(); // todo: split into more states like login/fonts
- coro_state = VOICE_STATE_DISCONNECT;
- break;
-
- case VOICE_STATE_DISCONNECT:
- LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL;
- endAndDisconnectSession();
- retry = 0; // Connected without issues
- coro_state = VOICE_STATE_WAIT_FOR_EXIT;
- break;
-
- case VOICE_STATE_WAIT_FOR_EXIT:
- if (isGatewayRunning())
- {
- LL_INFOS("Voice") << "waiting for SLVoice to exit" << LL_ENDL;
- llcoro::suspendUntilTimeout(1.0);
- }
- else if (mRelogRequested && mVoiceEnabled)
- {
- LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL;
- coro_state = VOICE_STATE_TP_WAIT;
- }
- else
- {
- coro_state = VOICE_STATE_DONE;
- }
- break;
-
- case VOICE_STATE_DONE:
- break;
- }
- } while (coro_state > 0);
-
- if (sShuttingDown)
- {
- // LLVivoxVoiceClient might be already dead
- return;
- }
-
- mIsCoroutineActive = false;
- LL_INFOS("Voice") << "exiting" << LL_ENDL;
-}
-
-bool LLVivoxVoiceClient::endAndDisconnectSession()
-{
- LL_DEBUGS("Voice") << LL_ENDL;
-
- breakVoiceConnection(true);
-
- killGateway();
-
- return true;
-}
-
-bool LLVivoxVoiceClient::callbackEndDaemon(const LLSD& data)
-{
- if (!sShuttingDown && mVoiceEnabled)
- {
- LL_WARNS("Voice") << "SLVoice terminated " << ll_stream_notation_sd(data) << LL_ENDL;
- terminateAudioSession(false);
- closeSocket();
- cleanUp();
- LLVoiceClient::getInstance()->setUserPTTState(false);
- gAgent.setVoiceConnected(false);
- mRelogRequested = true;
- }
- sGatewayPump.stopListening("VivoxDaemonPump");
- return false;
-}
-
-bool LLVivoxVoiceClient::startAndLaunchDaemon()
-{
- //---------------------------------------------------------------------
- if (!LLVoiceClient::getInstance()->voiceEnabled())
- {
- // Voice is locked out, we must not launch the vivox daemon.
- LL_WARNS("Voice") << "voice disabled; not starting daemon" << LL_ENDL;
- return false;
- }
-
- if (!isGatewayRunning())
- {
-#ifndef VIVOXDAEMON_REMOTEHOST
- // Launch the voice daemon
-#if LL_WINDOWS
- // On windows use exe (not work or RO) directory
- std::string exe_path = gDirUtilp->getExecutableDir();
- gDirUtilp->append(exe_path, "SLVoice.exe");
-#elif LL_DARWIN
- // On MAC use resource directory
- std::string exe_path = gDirUtilp->getAppRODataDir();
- gDirUtilp->append(exe_path, "SLVoice");
-#else
- std::string exe_path = gDirUtilp->getExecutableDir();
- gDirUtilp->append(exe_path, "SLVoice");
-#endif
- // See if the vivox executable exists
- llstat s;
- if (!LLFile::stat(exe_path, &s))
- {
- // vivox executable exists. Build the command line and launch the daemon.
- LLProcess::Params params;
- params.executable = exe_path;
-
- // VOICE-88: Cycle through [portbase..portbase+portrange) on
- // successive tries because attempting to relaunch (after manually
- // disabling and then re-enabling voice) with the same port can
- // cause SLVoice's bind() call to fail with EADDRINUSE. We expect
- // that eventually the OS will time out previous ports, which is
- // why we cycle instead of incrementing indefinitely.
-
- static LLCachedControl<U32> portbase(gSavedSettings, "VivoxVoicePort");
- static LLCachedControl<std::string> host(gSavedSettings, "VivoxVoiceHost");
- static LLCachedControl<std::string> loglevel(gSavedSettings, "VivoxDebugLevel");
- static LLCachedControl<std::string> log_folder(gSavedSettings, "VivoxLogDirectory");
- static LLCachedControl<std::string> shutdown_timeout(gSavedSettings, "VivoxShutdownTimeout");
- static const U32 portrange = 100;
- static U32 portoffset = 0;
- U32 port = 0;
-
- if (LLAppViewer::instance()->isSecondInstance())
- {
- // Ideally need to know amount of instances and
- // to increment instance_offset on EADDRINUSE.
- // But for now just use rand
- static U32 instance_offset = portrange * ll_rand(20);
- port = portbase + portoffset + instance_offset;
- }
- else
- {
- // leave main thread with exclusive port set
- port = portbase + portoffset;
- }
- portoffset = (portoffset + 1) % portrange;
- params.args.add("-i");
- params.args.add(STRINGIZE(host() << ':' << port));
-
- params.args.add("-ll");
- if (loglevel().empty())
- {
- params.args.add("0");
- }
- else
- {
- params.args.add(loglevel);
- }
-
- params.args.add("-lf");
- if (log_folder().empty())
- {
- params.args.add(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""));
- }
- else
- {
- params.args.add(log_folder);
- }
-
- // set log file basename and .log
- params.args.add("-lp");
- params.args.add("SLVoice");
- params.args.add("-ls");
- params.args.add(".log");
-
- // rotate any existing log
- std::string new_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.log");
- std::string old_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.old");
- if (gDirUtilp->fileExists(new_log))
- {
- LLFile::rename(new_log, old_log);
- }
-
- if (!shutdown_timeout().empty())
- {
- params.args.add("-st");
- params.args.add(shutdown_timeout);
- }
- params.cwd = gDirUtilp->getAppRODataDir();
-
-# ifdef VIVOX_HANDLE_ARGS
- params.args.add("-ah");
- params.args.add(LLVivoxSecurity::getInstance()->accountHandle());
-
- params.args.add("-ch");
- params.args.add(LLVivoxSecurity::getInstance()->connectorHandle());
-# endif // VIVOX_HANDLE_ARGS
-
- params.postend = sGatewayPump.getName();
- sGatewayPump.listen("VivoxDaemonPump", boost::bind(&LLVivoxVoiceClient::callbackEndDaemon, this, _1));
-
- LL_INFOS("Voice") << "Launching SLVoice" << LL_ENDL;
- LL_DEBUGS("Voice") << "SLVoice params " << params << LL_ENDL;
-
- sGatewayPtr = LLProcess::create(params);
-
- mDaemonHost = LLHost(host().c_str(), port);
- }
- else
- {
- LL_WARNS("Voice") << exe_path << " not found." << LL_ENDL;
- return false;
- }
-#else
- // SLIM SDK: port changed from 44124 to 44125.
- // We can connect to a client gateway running on another host. This is useful for testing.
- // To do this, launch the gateway on a nearby host like this:
- // vivox-gw.exe -p tcp -i 0.0.0.0:44125
- // and put that host's IP address here.
- mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost"), gSavedSettings.getU32("VivoxVoicePort"));
-#endif
-
- // Dirty the states we'll need to sync with the daemon when it comes up.
- mMuteMicDirty = true;
- mMicVolumeDirty = true;
- mSpeakerVolumeDirty = true;
- mSpeakerMuteDirty = true;
- // These only need to be set if they're not default (i.e. empty string).
- mCaptureDeviceDirty = !mCaptureDevice.empty();
- mRenderDeviceDirty = !mRenderDevice.empty();
-
- mMainSessionGroupHandle.clear();
- }
- else
- {
- LL_DEBUGS("Voice") << " gateway running; not attempting to start" << LL_ENDL;
- }
-
- //---------------------------------------------------------------------
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
-
- LL_DEBUGS("Voice") << "Connecting to vivox daemon:" << mDaemonHost << LL_ENDL;
-
- int retryCount(0);
- LLVoiceVivoxStats::getInstance()->reset();
- while (!sConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX)
- {
- LLVoiceVivoxStats::getInstance()->connectionAttemptStart();
- LL_DEBUGS("Voice") << "Attempting to connect to vivox daemon: " << mDaemonHost << LL_ENDL;
- closeSocket();
- if (!mSocket)
- {
- mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
- }
-
- sConnected = mSocket->blockingConnect(mDaemonHost);
- LLVoiceVivoxStats::getInstance()->connectionAttemptEnd(sConnected);
- if (!sConnected)
- {
- llcoro::suspendUntilTimeout(DAEMON_CONNECT_THROTTLE_SECONDS);
- }
- }
-
- //---------------------------------------------------------------------
- if (sShuttingDown && !sConnected)
- {
- return false;
- }
-
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
-
- while (!sPump && !sShuttingDown)
- { // Can't use the pump until we have it available.
- llcoro::suspendUntilNextFrame();
- }
-
- if (sShuttingDown)
- {
- return false;
- }
-
- // MBW -- Note to self: pumps and pipes examples in
- // indra/test/io.cpp
- // indra/test/llpipeutil.{cpp|h}
-
- // Attach the pumps and pipes
-
- LLPumpIO::chain_t readChain;
-
- readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket)));
- readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser()));
-
-
- sPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
-
-
- //---------------------------------------------------------------------
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
-
- // Initial devices query
- getCaptureDevicesSendMessage();
- getRenderDevicesSendMessage();
-
- mLoginRetryCount = 0;
-
- return true;
-}
-
-bool LLVivoxVoiceClient::provisionVoiceAccount()
-{
- LL_INFOS("Voice") << "Provisioning voice account." << LL_ENDL;
-
- while ((!gAgent.getRegion() || !gAgent.getRegion()->capabilitiesReceived()) && !sShuttingDown)
- {
- LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL;
- // *TODO* Pump a message for wake up.
- llcoro::suspend();
- }
-
- if (sShuttingDown)
- {
- return false;
- }
-
- std::string url = gAgent.getRegionCapability("ProvisionVoiceAccountRequest");
-
- LL_DEBUGS("Voice") << "region ready for voice provisioning; url=" << url << LL_ENDL;
-
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter = std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("voiceAccountProvision", httpPolicy);
- LLCore::HttpRequest::ptr_t httpRequest = std::make_shared<LLCore::HttpRequest>();
- LLCore::HttpOptions::ptr_t httpOpts = std::make_shared<LLCore::HttpOptions>();
- int retryCount(0);
-
- LLSD result;
- bool provisioned = false;
- do
- {
- LLVoiceVivoxStats::getInstance()->provisionAttemptStart();
- LLSD body;
- body["voice_server_type"] = "vivox";
- result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOpts);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
- if (status == LLCore::HttpStatus(404))
- {
- F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast<float>(retryCount));
- LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds. Retries: " << (S32)retryCount << LL_ENDL;
- llcoro::suspendUntilTimeout(timeout);
-
- if (sShuttingDown)
- {
- return false;
- }
- }
- else if (!status)
- {
- LL_WARNS("Voice") << "Unable to provision voice account." << LL_ENDL;
- LLVoiceVivoxStats::getInstance()->provisionAttemptEnd(false);
- return false;
- }
- else
- {
- provisioned = true;
- }
- } while (!provisioned && ++retryCount <= PROVISION_RETRY_MAX && !sShuttingDown);
-
- if (sShuttingDown && !provisioned)
- {
- return false;
- }
-
- LLVoiceVivoxStats::getInstance()->provisionAttemptEnd(provisioned);
- if (!provisioned)
- {
- LL_WARNS("Voice") << "Could not access voice provision cap after " << retryCount << " attempts." << LL_ENDL;
- return false;
- }
- LL_DEBUGS("Voice") << "Voice Provision Result." << result << LL_ENDL;
- std::string voiceSipUriHostname;
- std::string voiceAccountServerUri;
- std::string voiceUserName = result["username"].asString();
- std::string voicePassword = result["password"].asString();
-
- if (result.has("voice_sip_uri_hostname"))
- {
- voiceSipUriHostname = result["voice_sip_uri_hostname"].asString();
- }
-
- // this key is actually misnamed -- it will be an entire URI, not just a hostname.
- if (result.has("voice_account_server_name"))
- {
- voiceAccountServerUri = result["voice_account_server_name"].asString();
- }
-
- LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response"
- << " user " << (voiceUserName.empty() ? "not set" : "set")
- << " password " << (voicePassword.empty() ? "not set" : "set")
- << " sip uri " << voiceSipUriHostname
- << " account uri " << voiceAccountServerUri
- << LL_ENDL;
-
- setLoginInfo(voiceUserName, voicePassword, voiceSipUriHostname, voiceAccountServerUri);
-
- return true;
-}
-
-bool LLVivoxVoiceClient::establishVoiceConnection()
-{
- if (!mVoiceEnabled && mIsInitialized)
- {
- LL_WARNS("Voice") << "cannot establish connection; enabled "<<mVoiceEnabled<<" initialized "<<mIsInitialized<<LL_ENDL;
- return false;
- }
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LLSD result;
- bool connected(false);
- bool giving_up(false);
- int retries = 0;
- LL_INFOS("Voice") << "Requesting connection to voice service" << LL_ENDL;
-
- LLVoiceVivoxStats::getInstance()->establishAttemptStart();
- connectorCreate();
- do
- {
- result = llcoro::suspendUntilEventOn(mVivoxPump);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
-
- if (result.has("connector"))
- {
- connected = LLSD::Boolean(result["connector"]);
- LLVoiceVivoxStats::getInstance()->establishAttemptEnd(connected);
- if (!connected)
- {
- if (result.has("retry") && ++retries <= CONNECT_RETRY_MAX && !sShuttingDown)
- {
- F32 timeout = (F32)LLSD::Real(result["retry"]);
- timeout *= retries;
- LL_INFOS("Voice") << "Retry connection to voice service in " << timeout << " seconds" << LL_ENDL;
- llcoro::suspendUntilTimeout(timeout);
-
- if (mVoiceEnabled) // user may have switched it off
- {
- // try again
- LLVoiceVivoxStats::getInstance()->establishAttemptStart();
- connectorCreate();
- }
- else
- {
- // stop if they've turned off voice
- giving_up = true;
- }
- }
- else
- {
- giving_up=true;
- }
- }
- }
- LL_DEBUGS("Voice") << (connected ? "" : "not ") << "connected, "
- << (giving_up ? "" : "not ") << "giving up"
- << LL_ENDL;
- } while (!connected && !giving_up && !sShuttingDown);
-
- if (giving_up)
- {
- LLSD args;
- args["HOSTID"] = LLURI(mVoiceAccountServerURI).authority();
- LLNotificationsUtil::add("NoVoiceConnect", args);
- }
-
- return connected;
-}
-
-bool LLVivoxVoiceClient::breakVoiceConnection(bool corowait)
-{
- LL_DEBUGS("Voice") << "( wait=" << corowait << ")" << LL_ENDL;
- bool retval(true);
-
- mShutdownComplete = false;
- connectorShutdown();
-
- if (corowait)
- {
- LLSD timeoutResult(LLSDMap("connector", "timeout"));
-
- LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
-
- retval = result.has("connector");
- }
- else
- {
- mRelogRequested = false; //stop the control coro
- // If we are not doing a corowait then we must sleep until the connector has responded
- // otherwise we may very well close the socket too early.
-#if LL_WINDOWS
- if (!mShutdownComplete)
- {
- // The situation that brings us here is a call from ::terminate()
- // At this point message system is already down so we can't wait for
- // the message, yet we need to receive "connector shutdown response".
- // Either wait a bit and emulate it or check gMessageSystem for specific message
- _sleep(1000);
- if (sConnected)
- {
- sConnected = false;
- LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false)));
- mVivoxPump.post(vivoxevent);
- }
- mShutdownComplete = true;
- }
-#endif
- }
-
- LL_DEBUGS("Voice") << "closing SLVoice socket" << LL_ENDL;
- closeSocket(); // Need to do this now -- bad things happen if the destructor does it later.
- cleanUp();
- sConnected = false;
-
- return retval;
-}
-
-bool LLVivoxVoiceClient::loginToVivox()
-{
- LLSD timeoutResult(LLSDMap("login", "timeout"));
-
- int loginRetryCount(0);
-
- bool response_ok(false);
- bool account_login(false);
- bool send_login(true);
-
- do
- {
- mIsLoggingIn = true;
- if (send_login)
- {
- loginSendMessage();
- send_login = false;
- }
-
- LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGIN_ATTEMPT_TIMEOUT, timeoutResult);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
-
- if (result.has("login"))
- {
- std::string loginresp = result["login"];
-
- if (((loginresp == "retry") || (loginresp == "timeout")) && !sShuttingDown)
- {
- LL_WARNS("Voice") << "login failed with status '" << loginresp << "' "
- << " count " << loginRetryCount << "/" << LOGIN_RETRY_MAX
- << LL_ENDL;
- if (++loginRetryCount > LOGIN_RETRY_MAX)
- {
- // We've run out of retries - tell the user
- LL_WARNS("Voice") << "too many login retries (" << loginRetryCount << "); giving up." << LL_ENDL;
- LLSD args;
- args["HOSTID"] = LLURI(mVoiceAccountServerURI).authority();
- mTerminateDaemon = true;
- LLNotificationsUtil::add("NoVoiceConnect", args);
-
- mIsLoggingIn = false;
- return false;
- }
- response_ok = false;
- account_login = false;
- send_login = true;
-
- // an exponential backoff gets too long too quickly; stretch it out, but not too much
- F32 timeout = loginRetryCount * LOGIN_ATTEMPT_TIMEOUT;
-
- // tell the user there is a problem
- LL_WARNS("Voice") << "login " << loginresp << " will retry login in " << timeout << " seconds." << LL_ENDL;
-
- if (!sShuttingDown)
- {
- // Todo: this is way to long, viewer can get stuck waiting during shutdown
- // either make it listen to pump or split in smaller waits with checks for shutdown
- llcoro::suspendUntilTimeout(timeout);
- }
- }
- else if (loginresp == "failed")
- {
- mIsLoggingIn = false;
- return false;
- }
- else if (loginresp == "response_ok")
- {
- response_ok = true;
- }
- else if (loginresp == "account_login")
- {
- account_login = true;
- }
- else if (sShuttingDown)
- {
- mIsLoggingIn = false;
- return false;
- }
- }
-
- } while ((!response_ok || !account_login) && !sShuttingDown);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- mRelogRequested = false;
- mIsLoggedIn = true;
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
-
- // Set up the mute list observer if it hasn't been set up already.
- if ((!sMuteListListener_listening))
- {
- LLMuteList::getInstance()->addObserver(&mutelist_listener);
- sMuteListListener_listening = true;
- }
-
- // Set the initial state of mic mute, local speaker volume, etc.
- sendLocalAudioUpdates();
- mIsLoggingIn = false;
-
- return true;
-}
-
-void LLVivoxVoiceClient::logoutOfVivox(bool wait)
-{
- if (mIsLoggedIn)
- {
- // Ensure that we'll re-request provisioning before logging in again
- mAccountPassword.clear();
- mVoiceAccountServerURI.clear();
-
- logoutSendMessage();
-
- if (wait)
- {
- LLSD timeoutResult(LLSDMap("logout", "timeout"));
- LLSD result;
-
- do
- {
- LL_DEBUGS("Voice")
- << "waiting for logout response on "
- << mVivoxPump.getName()
- << LL_ENDL;
-
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult);
-
- if (sShuttingDown)
- {
- break;
- }
-
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- // Don't get confused by prior queued events -- note that it's
- // very important that mVivoxPump is an LLEventMailDrop, which
- // does queue events.
- } while (! result["logout"]);
- }
- else
- {
- LL_DEBUGS("Voice") << "not waiting for logout" << LL_ENDL;
- }
-
- mIsLoggedIn = false;
- }
-}
-
-
-bool LLVivoxVoiceClient::retrieveVoiceFonts()
-{
- // Request the set of available voice fonts.
- refreshVoiceEffectLists(true);
-
- mIsWaitingForFonts = true;
- LLSD result;
- do
- {
- result = llcoro::suspendUntilEventOn(mVivoxPump);
-
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- if (result.has("voice_fonts"))
- break;
- } while (true);
- mIsWaitingForFonts = false;
-
- mVoiceFontExpiryTimer.start();
- mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL);
-
- return result["voice_fonts"].asBoolean();
-}
-
-bool LLVivoxVoiceClient::requestParcelVoiceInfo()
-{
- //_INFOS("Voice") << "Requesting voice info for Parcel" << LL_ENDL;
-
- LLViewerRegion * region = gAgent.getRegion();
- if (region == NULL || !region->capabilitiesReceived())
- {
- LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest capability not yet available, deferring" << LL_ENDL;
- return false;
- }
-
- // grab the cap.
- std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
- if (url.empty())
- {
- // Region dosn't have the cap. Stop probing.
- LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest capability not available in this region" << LL_ENDL;
- return false;
- }
-
- // update the parcel
- checkParcelChanged(true);
-
- LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
-
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter = std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("parcelVoiceInfoRequest", httpPolicy);
- LLCore::HttpRequest::ptr_t httpRequest = std::make_shared<LLCore::HttpRequest>();
-
- LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD());
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
- if (mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized))
- {
- // if a terminate request has been received,
- // bail and go to the stateSessionTerminated
- // state. If the cap request is still pending,
- // the responder will check to see if we've moved
- // to a new session and won't change any state.
- LL_DEBUGS("Voice") << "terminate requested " << mSessionTerminateRequested
- << " enabled " << mVoiceEnabled
- << " initialized " << mIsInitialized
- << LL_ENDL;
- terminateAudioSession(true);
- return false;
- }
-
- if ((!status) || (mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)))
- {
- if (mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized))
- {
- LL_WARNS("Voice") << "Session terminated." << LL_ENDL;
- }
-
- LL_WARNS("Voice") << "No voice on parcel" << LL_ENDL;
- sessionTerminate();
- return false;
- }
-
- if (!result.has("voice_credentials"))
- {
- if (LLViewerParcelMgr::getInstance()->allowAgentVoice())
- {
- LL_WARNS("Voice") << "No voice credentials" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("Voice") << "No voice credentials" << LL_ENDL;
- }
- }
-
- // set the spatial channel. If no voice credentials or uri are
- // available, then we simply drop out of voice spatially.
- return setSpatialChannel(result["voice_credentials"]);
-}
-
-bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession)
-{
- mIsJoiningSession = true;
-
- sessionStatePtr_t oldSession = mAudioSession;
-
- LL_INFOS("Voice") << "Adding or joining voice session " << nextSession->mHandle << LL_ENDL;
-
- mAudioSession = nextSession;
- if (!mAudioSession || !mAudioSession->mReconnect)
- {
- mNextAudioSession.reset();
- }
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
-
- if (mAudioSession)
- {
- if (!mAudioSession->mHandle.empty())
- {
- // Connect to a session by session handle
-
- sessionMediaConnectSendMessage(mAudioSession);
- }
- else
- {
- // Connect to a session by URI
- sessionCreateSendMessage(mAudioSession, true, false);
- }
- }
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING);
-
- llcoro::suspend();
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LLSD result;
-
- if (mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM)
- {
- // Notify observers to let them know there is problem with voice
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- LL_WARNS() << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << LL_ENDL;
- }
-
- // Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for
- // example for p2p many times while waiting for response, so it can't be used to detect errors
- if (mAudioSession && mAudioSession->mIsSpatial)
- {
- mSpatialJoiningNum++;
- }
-
- if (!mVoiceEnabled && mIsInitialized)
- {
- LL_DEBUGS("Voice") << "Voice no longer enabled. Exiting"
- << " enabled " << mVoiceEnabled
- << " initialized " << mIsInitialized
- << LL_ENDL;
- mIsJoiningSession = false;
- // User bailed out during connect -- jump straight to teardown.
- terminateAudioSession(true);
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- return false;
- }
- else if (mSessionTerminateRequested)
- {
- LL_DEBUGS("Voice") << "Terminate requested" << LL_ENDL;
- if (mAudioSession && !mAudioSession->mHandle.empty())
- {
- // Only allow direct exits from this state in p2p calls (for cancelling an invite).
- // Terminating a half-connected session on other types of calls seems to break something in the vivox gateway.
- if (mAudioSession->mIsP2P)
- {
- terminateAudioSession(true);
- mIsJoiningSession = false;
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
- return false;
- }
- }
- }
-
- bool added(true);
- bool joined(false);
-
- LLSD timeoutResult(LLSDMap("session", "timeout"));
-
- // We are about to start a whole new session. Anything that MIGHT still be in our
- // maildrop is going to be stale and cause us much wailing and gnashing of teeth.
- // Just flush it all out and start new.
- mVivoxPump.discard();
-
- // It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4
- // before continuing from this state. They can happen in either order, and if I don't wait for both, things can get stuck.
- // For now, the SessionGroup.AddSession response handler sets mSessionHandle and the SessionStateChangeEvent handler transitions to stateSessionJoined.
- // This is a cheap way to make sure both have happened before proceeding.
- do
- {
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, SESSION_JOIN_TIMEOUT, timeoutResult);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LL_INFOS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- if (result.has("session"))
- {
- if (!mAudioSession)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while session is not initialized." << LL_ENDL;
- continue;
- }
- if (result.has("handle") && result["handle"] != mAudioSession->mHandle)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while waiting for \"" << mAudioSession->mHandle << "\"." << LL_ENDL;
- continue;
- }
-
- std::string message = result["session"].asString();
-
- if ((message == "added") || (message == "created"))
- {
- added = true;
- }
- else if (message == "joined")
- {
- joined = true;
- }
- else if ((message == "failed") || (message == "removed") || (message == "timeout"))
- { // we will get a removed message if a voice call is declined.
- LL_INFOS("Voice") << "Result:" << result << LL_ENDL;
- if (message == "failed")
- {
- int reason = result["reason"].asInteger();
- LL_WARNS("Voice") << "Add and join failed for reason " << reason << LL_ENDL;
-
- if ( (reason == ERROR_VIVOX_NOT_LOGGED_IN)
- || (reason == ERROR_VIVOX_OBJECT_NOT_FOUND))
- {
- LL_DEBUGS("Voice") << "Requesting reprovision and login." << LL_ENDL;
- requestRelog();
- }
- }
- else
- {
- LL_WARNS("Voice") << "session '" << message << "' "
- << LL_ENDL;
- }
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
- mIsJoiningSession = false;
- return false;
- }
- }
- } while (!added || !joined);
-
- mIsJoiningSession = false;
-
- if (mSpatialJoiningNum > 100)
- {
- LL_WARNS("Voice") << "There seems to be problem with connecting to a voice channel. Frames to join were " << mSpatialJoiningNum << LL_ENDL;
- }
-
- mSpatialJoiningNum = 0;
-
- // Events that need to happen when a session is joined could go here.
- // send an initial positional information immediately upon joining.
- //
- // do an initial update for position and the camera position, then send a
- // positional update.
- updatePosition();
- enforceTether();
-
- // Dirty state that may need to be sync'ed with the daemon.
- mMuteMicDirty = true;
- mSpeakerVolumeDirty = true;
- mSpatialCoordsDirty = true;
-
- sendPositionAndVolumeUpdate();
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED);
-
- return true;
-}
-
-bool LLVivoxVoiceClient::terminateAudioSession(bool wait)
-{
-
- if (mAudioSession)
- {
- LL_INFOS("Voice") << "terminateAudioSession(" << wait << ") Terminating current voice session " << mAudioSession->mHandle << LL_ENDL;
-
- if (mIsLoggedIn)
- {
- if (!mAudioSession->mHandle.empty())
- {
-
-#if RECORD_EVERYTHING
- // HACK: for testing only
- // Save looped recording
- std::string savepath("/tmp/vivoxrecording");
- {
- time_t now = time(NULL);
- const size_t BUF_SIZE = 64;
- char time_str[BUF_SIZE]; /* Flawfinder: ignore */
-
- strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
- savepath += time_str;
- }
- recordingLoopSave(savepath);
-#endif
-
- sessionMediaDisconnectSendMessage(mAudioSession);
-
- if (wait)
- {
- LLSD result;
- do
- {
- LLSD timeoutResult(LLSDMap("session", "timeout"));
-
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- if (result.has("session"))
- {
- if (result.has("handle"))
- {
- if (result["handle"] != mAudioSession->mHandle)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while waiting for \"" << mAudioSession->mHandle << "\"." << LL_ENDL;
- continue;
- }
- }
-
- std::string message = result["session"].asString();
- if (message == "removed" || message == "timeout")
- break;
- }
- } while (true);
-
- }
- }
- else
- {
- LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS("Voice") << "Session " << mAudioSession->mHandle << " already terminated by logout." << LL_ENDL;
- }
-
- sessionStatePtr_t oldSession = mAudioSession;
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL); // needs mAudioSession for uri
- mAudioSession.reset();
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
- }
- else
- {
- LL_WARNS("Voice") << "terminateAudioSession(" << wait << ") with NULL mAudioSession" << LL_ENDL;
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
- }
-
-
- // Always reset the terminate request flag when we get here.
- // Some slower PCs have a race condition where they can switch to an incoming P2P call faster than the state machine leaves
- // the region chat.
- mSessionTerminateRequested = false;
-
- bool status=((mVoiceEnabled || !mIsInitialized) && !mRelogRequested && !sShuttingDown);
- LL_DEBUGS("Voice") << "exiting"
- << " VoiceEnabled " << mVoiceEnabled
- << " IsInitialized " << mIsInitialized
- << " RelogRequested " << mRelogRequested
- << " ShuttingDown " << (sShuttingDown ? "True" : "False")
- << " returning " << status
- << LL_ENDL;
- return status;
-}
-
-
-typedef enum e_voice_wait_for_channel_state
-{
- VOICE_CHANNEL_STATE_LOGIN = 0, // entry point
- VOICE_CHANNEL_STATE_CHECK_EFFECTS,
- VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING,
- VOICE_CHANNEL_STATE_PROCESS_CHANNEL,
- VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY,
- VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK,
- VOICE_CHANNEL_STATE_LOGOUT,
- VOICE_CHANNEL_STATE_RELOG,
- VOICE_CHANNEL_STATE_DONE,
-} EVoiceWaitForChannelState;
-
-bool LLVivoxVoiceClient::waitForChannel()
-{
- LL_INFOS("Voice") << "Waiting for channel" << LL_ENDL;
-
- EVoiceWaitForChannelState state = VOICE_CHANNEL_STATE_LOGIN;
-
- do
- {
- if (sShuttingDown)
- {
- // terminate() forcefully disconects voice, no need for cleanup
- return false;
- }
-
- switch (state)
- {
- case VOICE_CHANNEL_STATE_LOGIN:
- if (!loginToVivox())
- {
- return false;
- }
- state = VOICE_CHANNEL_STATE_CHECK_EFFECTS;
- break;
-
- case VOICE_CHANNEL_STATE_CHECK_EFFECTS:
- if (LLVoiceClient::instance().getVoiceEffectEnabled())
- {
- retrieveVoiceFonts();
-
- if (sShuttingDown)
- {
- return false;
- }
-
- // Request the set of available voice fonts.
- refreshVoiceEffectLists(false);
- }
-
-#if USE_SESSION_GROUPS
- // Rider: This code is completely unchanged from the original state machine
- // It does not seem to be in active use... but I'd rather not rip it out.
- // create the main session group
- setState(stateCreatingSessionGroup);
- sessionGroupCreateSendMessage();
-#endif
-
- state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING;
- break;
-
- case VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING:
- llcoro::suspend();
- state = VOICE_CHANNEL_STATE_PROCESS_CHANNEL;
- break;
-
- case VOICE_CHANNEL_STATE_PROCESS_CHANNEL:
- if (mTuningMode)
- {
- performMicTuning();
- }
- else if (mCaptureBufferMode)
- {
- recordingAndPlaybackMode();
- }
- else if (mProcessChannels && ((mNextAudioSession == NULL) || checkParcelChanged()))
- {
- // the parcel is changed, or we have no pending audio sessions,
- // so try to request the parcel voice info
- // if we have the cap, we move to the appropriate state
- requestParcelVoiceInfo(); //suspends for http reply
- }
- else if (sessionNeedsRelog(mNextAudioSession))
- {
- LL_INFOS("Voice") << "Session requesting reprovision and login." << LL_ENDL;
- requestRelog();
- break;
- }
- else if (mNextAudioSession)
- {
- if (!mNextAudioSession->mIsP2P && !mProcessChannels)
- {
- llcoro::suspend();
- break;
- }
-
- try
- {
- sessionStatePtr_t joinSession = mNextAudioSession;
- mNextAudioSession.reset();
- mIsProcessingChannels = true;
- if (!runSession(joinSession)) //suspends
- {
- mIsProcessingChannels = false;
- LL_DEBUGS("Voice") << "runSession returned false; leaving inner loop" << LL_ENDL;
- break;
- }
- else
- {
- mIsProcessingChannels = false;
- LL_DEBUGS("Voice")
- << "runSession returned true to inner loop"
- << " RelogRequested=" << mRelogRequested
- << " VoiceEnabled=" << mVoiceEnabled
- << LL_ENDL;
- }
- }
- catch (const LLCoros::Stop&)
- {
- LL_DEBUGS("LLVivoxVoiceClient") << "Received a shutdown exception" << LL_ENDL;
- }
- catch (const LLContinueError&)
- {
- LOG_UNHANDLED_EXCEPTION("LLVivoxVoiceClient");
- }
- catch (...)
- {
- // Ideally for Windows need to log SEH exception instead or to set SEH
- // handlers but bugsplat shows local variables for windows, which should
- // be enough
- LL_WARNS("Voice") << "voiceControlStateMachine crashed in state VOICE_CHANNEL_STATE_PROCESS_CHANNEL"
- << " mRelogRequested " << mRelogRequested
- << " mVoiceEnabled " << mVoiceEnabled
- << " mIsProcessingChannels " << mIsProcessingChannels
- << " mProcessChannels " << mProcessChannels
- << LL_ENDL;
- throw;
- }
- }
-
- state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY;
- break;
-
- case VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY:
- if (!mNextAudioSession)
- {
- llcoro::suspendUntilTimeout(1.0);
- }
- state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK;
- break;
-
- case VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK:
- if (mVoiceEnabled && !mRelogRequested)
- {
- state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING;
- break;
- }
- else
- {
- mIsProcessingChannels = false;
- LL_DEBUGS("Voice")
- << "leaving inner waitForChannel loop"
- << " RelogRequested=" << mRelogRequested
- << " VoiceEnabled=" << mVoiceEnabled
- << LL_ENDL;
- state = VOICE_CHANNEL_STATE_LOGOUT;
- break;
- }
-
- case VOICE_CHANNEL_STATE_LOGOUT:
- logoutOfVivox(true /*bool wait*/);
- if (mRelogRequested)
- {
- state = VOICE_CHANNEL_STATE_RELOG;
- }
- else
- {
- state = VOICE_CHANNEL_STATE_DONE;
- }
- break;
-
- case VOICE_CHANNEL_STATE_RELOG:
- LL_DEBUGS("Voice") << "Relog Requested, restarting provisioning" << LL_ENDL;
- if (!provisionVoiceAccount())
- {
- if (sShuttingDown)
- {
- return false;
- }
- LL_WARNS("Voice") << "provisioning voice failed; giving up" << LL_ENDL;
- giveUp();
- return false;
- }
- if (mVoiceEnabled && mRelogRequested && isGatewayRunning())
- {
- state = VOICE_CHANNEL_STATE_LOGIN;
- }
- else
- {
- state = VOICE_CHANNEL_STATE_DONE;
- }
- break;
- case VOICE_CHANNEL_STATE_DONE:
- LL_DEBUGS("Voice")
- << "exiting"
- << " RelogRequested=" << mRelogRequested
- << " VoiceEnabled=" << mVoiceEnabled
- << LL_ENDL;
- return !sShuttingDown;
- }
- } while (true);
-}
-
-bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session)
-{
- LL_INFOS("Voice") << "running new voice session " << session->mHandle << LL_ENDL;
-
- if (sShuttingDown || !mProcessChannels)
- {
- return false;
- }
-
- bool joined_session = addAndJoinSession(session);
-
- if (!joined_session)
- {
- notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
-
- if (mSessionTerminateRequested)
- {
- LL_DEBUGS("Voice") << "runSession terminate requested " << LL_ENDL;
- terminateAudioSession(true);
- }
- // if a relog has been requested then addAndJoineSession
- // failed in a spectacular way and we need to back out.
- // If this is not the case then we were simply trying to
- // make a call and the other party rejected it.
- return !mRelogRequested;
- }
-
- notifyParticipantObservers();
- notifyVoiceFontObservers();
-
- LLSD timeoutEvent(LLSDMap("timeout", LLSD::Boolean(true)));
-
- mIsInChannel = true;
- mMuteMicDirty = true;
-
- while (!sShuttingDown
- && mVoiceEnabled
- && isGatewayRunning()
- && !mSessionTerminateRequested
- && !mTuningMode
- && mProcessChannels)
- {
- sendCaptureAndRenderDevices(); // suspends
-
- if (sShuttingDown)
- {
- return false;
- }
-
- if (mSessionTerminateRequested)
- {
- break;
- }
-
- if (mAudioSession && mAudioSession->mParticipantsChanged)
- {
- mAudioSession->mParticipantsChanged = false;
- notifyParticipantObservers();
- }
-
- if (!inSpatialChannel())
- {
- // When in a non-spatial channel, never send positional updates.
- mSpatialCoordsDirty = false;
- }
- else
- {
- updatePosition();
-
- if (checkParcelChanged())
- {
- // *RIDER: I think I can just return here if the parcel has changed
- // and grab the new voice channel from the outside loop.
- //
- // if the parcel has changed, attempted to request the
- // cap for the parcel voice info. If we can't request it
- // then we don't have the cap URL so we do nothing and will
- // recheck next time around
- if (requestParcelVoiceInfo()) // suspends
- { // The parcel voice URI has changed.. break out and reconnect.
- break;
- }
-
- if (sShuttingDown)
- {
- return false;
- }
- }
- // Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position)
- enforceTether();
- }
- sendPositionAndVolumeUpdate();
-
- // Do notifications for expiring Voice Fonts.
- if (mVoiceFontExpiryTimer.hasExpired())
- {
- expireVoiceFonts();
- mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL);
- }
-
- // send any requests to adjust mic and speaker settings if they have changed
- sendLocalAudioUpdates();
-
- mIsInitialized = true;
- LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, UPDATE_THROTTLE_SECONDS, timeoutEvent);
-
- if (sShuttingDown)
- {
- return false;
- }
-
- if (!result.has("timeout")) // logging the timeout event spams the log
- {
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- }
- if (result.has("session"))
- {
- if (result.has("handle"))
- {
- if (!mAudioSession)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while session is not initiated." << LL_ENDL;
- continue;
- }
- if (result["handle"] != mAudioSession->mHandle)
- {
- LL_WARNS("Voice") << "Message for session handle \"" << result["handle"] << "\" while waiting for \"" << mAudioSession->mHandle << "\"." << LL_ENDL;
- continue;
- }
- }
-
- std::string message = result["session"];
-
- if (message == "removed")
- {
- LL_DEBUGS("Voice") << "session removed" << LL_ENDL;
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
- break;
- }
- }
- else if (result.has("login"))
- {
- std::string message = result["login"];
- if (message == "account_logout")
- {
- LL_DEBUGS("Voice") << "logged out" << LL_ENDL;
- mIsLoggedIn = false;
- mRelogRequested = true;
- break;
- }
- }
- }
-
- if (sShuttingDown)
- {
- return false;
- }
-
- mIsInChannel = false;
- LL_DEBUGS("Voice") << "terminating at end of runSession" << LL_ENDL;
- terminateAudioSession(true);
-
- return true;
-}
-
-void LLVivoxVoiceClient::sendCaptureAndRenderDevices()
-{
- if (mCaptureDeviceDirty || mRenderDeviceDirty)
- {
- std::ostringstream stream;
-
- buildSetCaptureDevice(stream);
- buildSetRenderDevice(stream);
-
- if (!stream.str().empty())
- {
- writeString(stream.str());
- }
-
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
- }
-}
-
-void LLVivoxVoiceClient::recordingAndPlaybackMode()
-{
- LL_INFOS("Voice") << "In voice capture/playback mode." << LL_ENDL;
-
- while (true)
- {
- LLSD command;
- do
- {
- command = llcoro::suspendUntilEventOn(mVivoxPump);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(command) << LL_ENDL;
- } while (!command.has("recplay"));
-
- if (command["recplay"].asString() == "quit")
- {
- mCaptureBufferMode = false;
- break;
- }
- else if (command["recplay"].asString() == "record")
- {
- voiceRecordBuffer();
- }
- else if (command["recplay"].asString() == "playback")
- {
- voicePlaybackBuffer();
- }
- }
-
- LL_INFOS("Voice") << "Leaving capture/playback mode." << LL_ENDL;
- mCaptureBufferRecording = false;
- mCaptureBufferRecorded = false;
- mCaptureBufferPlaying = false;
-
- return;
-}
-
-int LLVivoxVoiceClient::voiceRecordBuffer()
-{
- LLSD timeoutResult(LLSDMap("recplay", "stop"));
-
- LL_INFOS("Voice") << "Recording voice buffer" << LL_ENDL;
-
- LLSD result;
-
- captureBufferRecordStartSendMessage();
- notifyVoiceFontObservers();
-
- do
- {
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, CAPTURE_BUFFER_MAX_TIME, timeoutResult);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- } while (!result.has("recplay"));
-
- mCaptureBufferRecorded = true;
-
- captureBufferRecordStopSendMessage();
- mCaptureBufferRecording = false;
-
- // Update UI, should really use a separate callback.
- notifyVoiceFontObservers();
-
- return true;
- /*TODO expand return to move directly into play*/
-}
-
-int LLVivoxVoiceClient::voicePlaybackBuffer()
-{
- LLSD timeoutResult(LLSDMap("recplay", "stop"));
-
- LL_INFOS("Voice") << "Playing voice buffer" << LL_ENDL;
-
- LLSD result;
-
- do
- {
- captureBufferPlayStartSendMessage(mPreviewVoiceFont);
-
- // Store the voice font being previewed, so that we know to restart if it changes.
- mPreviewVoiceFontLast = mPreviewVoiceFont;
-
- do
- {
- // Update UI, should really use a separate callback.
- notifyVoiceFontObservers();
-
- result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, CAPTURE_BUFFER_MAX_TIME, timeoutResult);
- LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL;
- } while (!result.has("recplay"));
-
- if (result["recplay"] == "playback")
- continue; // restart playback... May be a font change.
-
- break;
- } while (true);
-
- // Stop playing.
- captureBufferPlayStopSendMessage();
- mCaptureBufferPlaying = false;
-
- // Update UI, should really use a separate callback.
- notifyVoiceFontObservers();
-
- return true;
-}
-
-
-bool LLVivoxVoiceClient::performMicTuning()
-{
- LL_INFOS("Voice") << "Entering voice tuning mode." << LL_ENDL;
- mIsInTuningMode = true;
-
- while (mTuningMode && !sShuttingDown)
- {
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
- }
-
- mIsInTuningMode = false;
-
- //---------------------------------------------------------------------
- return true;
-}
-
-//=========================================================================
-
-void LLVivoxVoiceClient::closeSocket(void)
-{
- mSocket.reset();
- sConnected = false;
- mConnectorEstablished = false;
- mAccountLoggedIn = false;
-}
-
-void LLVivoxVoiceClient::loginSendMessage()
-{
- std::ostringstream stream;
-
- bool autoPostCrashDumps = gSavedSettings.getBOOL("VivoxAutoPostCrashDumps");
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Login.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<AccountName>" << mAccountName << "</AccountName>"
- << "<AccountPassword>" << mAccountPassword << "</AccountPassword>"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>"
- << "<EnableBuddiesAndPresence>false</EnableBuddiesAndPresence>"
- << "<EnablePresencePersistence>0</EnablePresencePersistence>"
- << "<BuddyManagementMode>Application</BuddyManagementMode>"
- << "<ParticipantPropertyFrequency>5</ParticipantPropertyFrequency>"
- << (autoPostCrashDumps?"<AutopostCrashDumps>true</AutopostCrashDumps>":"")
- << "</Request>\n\n\n";
-
- LL_INFOS("Voice") << "Attempting voice login" << LL_ENDL;
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::logout()
-{
- // Ensure that we'll re-request provisioning before logging in again
- mAccountPassword.clear();
- mVoiceAccountServerURI.clear();
-
- logoutSendMessage();
-}
-
-void LLVivoxVoiceClient::logoutSendMessage()
-{
- if(mAccountLoggedIn)
- {
- LL_INFOS("Voice") << "Attempting voice logout" << LL_ENDL;
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Logout.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- mAccountLoggedIn = false;
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::sessionGroupCreateSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "creating session group" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Create.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "<Type>Normal</Type>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::sessionCreateSendMessage(const sessionStatePtr_t &session, bool startAudio, bool startText)
-{
- S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
- LL_DEBUGS("Voice") << "Requesting create: " << session->mSIPURI
- << " with voice font: " << session->mVoiceFontID << " (" << font_index << ")"
- << LL_ENDL;
-
- session->mCreateInProgress = true;
- if(startAudio)
- {
- session->mMediaConnectInProgress = true;
- }
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << session->mSIPURI << "\" action=\"Session.Create.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "<URI>" << session->mSIPURI << "</URI>";
-
- static const std::string allowed_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-._~";
-
- if(!session->mHash.empty())
- {
- stream
- << "<Password>" << LLURI::escape(session->mHash, allowed_chars) << "</Password>"
- << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>";
- }
-
- stream
- << "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
- << "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
- << "<Name>" << mChannelName << "</Name>"
- << "</Request>\n\n\n";
- LL_WARNS("Voice") << "Session.Create: " << stream.str() << LL_ENDL;
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionGroupAddSessionSendMessage(const sessionStatePtr_t &session, bool startAudio, bool startText)
-{
- LL_DEBUGS("Voice") << "Requesting create: " << session->mSIPURI << LL_ENDL;
-
- S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
- LL_DEBUGS("Voice") << "With voice font: " << session->mVoiceFontID << " (" << font_index << ")" << LL_ENDL;
-
- session->mCreateInProgress = true;
- if(startAudio)
- {
- session->mMediaConnectInProgress = true;
- }
-
- std::string password;
- if(!session->mHash.empty())
- {
- static const std::string allowed_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-._~"
- ;
- password = LLURI::escape(session->mHash, allowed_chars);
- }
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << session->mSIPURI << "\" action=\"SessionGroup.AddSession.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<URI>" << session->mSIPURI << "</URI>"
- << "<Name>" << mChannelName << "</Name>"
- << "<ConnectAudio>" << (startAudio?"true":"false") << "</ConnectAudio>"
- << "<ConnectText>" << (startText?"true":"false") << "</ConnectText>"
- << "<Password>" << password << "</Password>"
- << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>"
- << "</Request>\n\n\n"
- ;
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionMediaConnectSendMessage(const sessionStatePtr_t &session)
-{
- S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
- LL_DEBUGS("Voice") << "Connecting audio to session handle: " << session->mHandle
- << " with voice font: " << session->mVoiceFontID << " (" << font_index << ")"
- << LL_ENDL;
-
- session->mMediaConnectInProgress = true;
-
- std::ostringstream stream;
-
- stream
- << "<Request requestId=\"" << session->mHandle << "\" action=\"Session.MediaConnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<Media>Audio</Media>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionTextConnectSendMessage(const sessionStatePtr_t &session)
-{
- LL_DEBUGS("Voice") << "connecting text to session handle: " << session->mHandle << LL_ENDL;
-
- std::ostringstream stream;
-
- stream
- << "<Request requestId=\"" << session->mHandle << "\" action=\"Session.TextConnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionTerminate()
-{
- mSessionTerminateRequested = true;
-}
-
-void LLVivoxVoiceClient::requestRelog()
-{
- mSessionTerminateRequested = true;
- mRelogRequested = true;
-}
-
-
-void LLVivoxVoiceClient::leaveAudioSession()
-{
- if(mAudioSession)
- {
- LL_DEBUGS("Voice") << "leaving session: " << mAudioSession->mSIPURI << LL_ENDL;
-
- if(!mAudioSession->mHandle.empty())
- {
-
-#if RECORD_EVERYTHING
- // HACK: for testing only
- // Save looped recording
- std::string savepath("/tmp/vivoxrecording");
- {
- time_t now = time(NULL);
- const size_t BUF_SIZE = 64;
- char time_str[BUF_SIZE]; /* Flawfinder: ignore */
-
- strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
- savepath += time_str;
- }
- recordingLoopSave(savepath);
-#endif
-
- sessionMediaDisconnectSendMessage(mAudioSession);
- }
- else
- {
- LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS("Voice") << "called with no active session" << LL_ENDL;
- }
- sessionTerminate();
-}
-
-void LLVivoxVoiceClient::sessionTerminateSendMessage(const sessionStatePtr_t &session)
-{
- std::ostringstream stream;
-
- sessionGroupTerminateSendMessage(session);
- return;
- /*
- LL_DEBUGS("Voice") << "Sending Session.Terminate with handle " << session->mHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Terminate.1\">"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- */
-}
-
-void LLVivoxVoiceClient::sessionGroupTerminateSendMessage(const sessionStatePtr_t &session)
-{
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Sending SessionGroup.Terminate with handle " << session->mGroupHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Terminate.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::sessionMediaDisconnectSendMessage(const sessionStatePtr_t &session)
-{
- std::ostringstream stream;
- sessionGroupTerminateSendMessage(session);
- return;
- /*
- LL_DEBUGS("Voice") << "Sending Session.MediaDisconnect with handle " << session->mHandle << LL_ENDL;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.MediaDisconnect.1\">"
- << "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<Media>Audio</Media>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- */
-
-}
-
-
-void LLVivoxVoiceClient::getCaptureDevicesSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetCaptureDevices.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::getRenderDevicesSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetRenderDevices.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::clearCaptureDevices()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
- mCaptureDevices.clear();
-}
-
-void LLVivoxVoiceClient::addCaptureDevice(const LLVoiceDevice& device)
-{
- LL_DEBUGS("Voice") << "display: '" << device.display_name << "' device: '" << device.full_name << "'" << LL_ENDL;
- mCaptureDevices.push_back(device);
-}
-
-LLVoiceDeviceList& LLVivoxVoiceClient::getCaptureDevices()
-{
- return mCaptureDevices;
-}
-
-void LLVivoxVoiceClient::setCaptureDevice(const std::string& name)
-{
- if(name == "Default")
- {
- if(!mCaptureDevice.empty())
- {
- mCaptureDevice.clear();
- mCaptureDeviceDirty = true;
- }
- }
- else
- {
- if(mCaptureDevice != name)
- {
- mCaptureDevice = name;
- mCaptureDeviceDirty = true;
- }
- }
-}
-void LLVivoxVoiceClient::setDevicesListUpdated(bool state)
-{
- mDevicesListUpdated = state;
-}
-
-void LLVivoxVoiceClient::clearRenderDevices()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
- mRenderDevices.clear();
-}
-
-void LLVivoxVoiceClient::addRenderDevice(const LLVoiceDevice& device)
-{
- LL_DEBUGS("Voice") << "display: '" << device.display_name << "' device: '" << device.full_name << "'" << LL_ENDL;
- mRenderDevices.push_back(device);
-}
-
-LLVoiceDeviceList& LLVivoxVoiceClient::getRenderDevices()
-{
- return mRenderDevices;
-}
-
-void LLVivoxVoiceClient::setRenderDevice(const std::string& name)
-{
- if(name == "Default")
- {
- if(!mRenderDevice.empty())
- {
- mRenderDevice.clear();
- mRenderDeviceDirty = true;
- }
- }
- else
- {
- if(mRenderDevice != name)
- {
- mRenderDevice = name;
- mRenderDeviceDirty = true;
- }
- }
-
-}
-
-void LLVivoxVoiceClient::tuningStart()
-{
- LL_DEBUGS("Voice") << "Starting tuning" << LL_ENDL;
- mTuningMode = true;
- if (!mIsCoroutineActive)
- {
- LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro",
- boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance()));
- }
- else if (mIsInChannel)
- {
- LL_DEBUGS("Voice") << "no channel" << LL_ENDL;
- sessionTerminate();
- }
-}
-
-void LLVivoxVoiceClient::tuningStop()
-{
- mTuningMode = false;
- // force a renegotiation.
- mCurrentParcelLocalID = 0;
- mCurrentRegionName = "";
-}
-
-bool LLVivoxVoiceClient::inTuningMode()
-{
- return mIsInTuningMode;
-}
-
-void LLVivoxVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool loop)
-{
- mTuningAudioFile = name;
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStart.1\">"
- << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
- << "<Loop>" << (loop?"1":"0") << "</Loop>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::tuningRenderStopSendMessage()
-{
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
- << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::tuningCaptureStartSendMessage(int loop)
-{
- LL_DEBUGS("Voice") << "sending CaptureAudioStart" << LL_ENDL;
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStart.1\">"
- << "<Duration>-1</Duration>"
- << "<LoopToRenderDevice>" << loop << "</LoopToRenderDevice>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::tuningCaptureStopSendMessage()
-{
- LL_DEBUGS("Voice") << "sending CaptureAudioStop" << LL_ENDL;
-
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-
- mTuningEnergy = 0.0f;
-}
-
-void LLVivoxVoiceClient::tuningSetMicVolume(float volume)
-{
- int scaled_volume = scale_mic_volume(volume);
-
- if(scaled_volume != mTuningMicVolume)
- {
- mTuningMicVolume = scaled_volume;
- mTuningMicVolumeDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::tuningSetSpeakerVolume(float volume)
-{
- int scaled_volume = scale_speaker_volume(volume);
-
- if(scaled_volume != mTuningSpeakerVolume)
- {
- mTuningSpeakerVolume = scaled_volume;
- mTuningSpeakerVolumeDirty = true;
- }
-}
-
-float LLVivoxVoiceClient::tuningGetEnergy(void)
-{
- return mTuningEnergy;
-}
-
-bool LLVivoxVoiceClient::deviceSettingsAvailable()
-{
- bool result = true;
-
- if(!sConnected)
- result = false;
-
- if(mRenderDevices.empty())
- result = false;
-
- return result;
-}
-bool LLVivoxVoiceClient::deviceSettingsUpdated()
-{
- bool updated = mDevicesListUpdated;
- if (mDevicesListUpdated)
- {
- // a hot swap event or a polling of the audio devices has been parsed since the last redraw of the input and output device panel.
- mDevicesListUpdated = false; // toggle the setting
- }
- return updated;
-}
-
-void LLVivoxVoiceClient::refreshDeviceLists(bool clearCurrentList)
-{
- if(clearCurrentList)
- {
- clearCaptureDevices();
- clearRenderDevices();
- }
- getCaptureDevicesSendMessage();
- getRenderDevicesSendMessage();
-}
-
-void LLVivoxVoiceClient::daemonDied()
-{
- // The daemon died, so the connection is gone. Reset everything and start over.
- LL_WARNS("Voice") << "Connection to vivox daemon lost. Resetting state."<< LL_ENDL;
-
- //TODO: Try to relaunch the daemon
-}
-
-void LLVivoxVoiceClient::giveUp()
-{
- // All has failed. Clean up and stop trying.
- LL_WARNS("Voice") << "Terminating Voice Service" << LL_ENDL;
- closeSocket();
- cleanUp();
-}
-
-static void oldSDKTransform (LLVector3 &left, LLVector3 &up, LLVector3 &at, LLVector3d &pos, LLVector3 &vel)
-{
- F32 nat[3], nup[3], nl[3]; // the new at, up, left vectors and the new position and velocity
-// F32 nvel[3];
- F64 npos[3];
-
- // The original XML command was sent like this:
- /*
- << "<Position>"
- << "<X>" << pos[VX] << "</X>"
- << "<Y>" << pos[VZ] << "</Y>"
- << "<Z>" << pos[VY] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << mAvatarVelocity[VX] << "</X>"
- << "<Y>" << mAvatarVelocity[VZ] << "</Y>"
- << "<Z>" << mAvatarVelocity[VY] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << l.mV[VX] << "</X>"
- << "<Y>" << u.mV[VX] << "</Y>"
- << "<Z>" << a.mV[VX] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << l.mV[VZ] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VY] << "</X>"
- << "<Y>" << u.mV [VZ] << "</Y>"
- << "<Z>" << a.mV [VY] << "</Z>"
- << "</LeftOrientation>";
- */
-
-#if 1
- // This was the original transform done when building the XML command
- nat[0] = left.mV[VX];
- nat[1] = up.mV[VX];
- nat[2] = at.mV[VX];
-
- nup[0] = left.mV[VZ];
- nup[1] = up.mV[VY];
- nup[2] = at.mV[VZ];
-
- nl[0] = left.mV[VY];
- nl[1] = up.mV[VZ];
- nl[2] = at.mV[VY];
-
- npos[0] = pos.mdV[VX];
- npos[1] = pos.mdV[VZ];
- npos[2] = pos.mdV[VY];
-
-// nvel[0] = vel.mV[VX];
-// nvel[1] = vel.mV[VZ];
-// nvel[2] = vel.mV[VY];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-
- // This was the original transform done in the SDK
- nat[0] = at.mV[2];
- nat[1] = 0; // y component of at vector is always 0, this was up[2]
- nat[2] = -1 * left.mV[2];
-
- // We override whatever the application gives us
- nup[0] = 0; // x component of up vector is always 0
- nup[1] = 1; // y component of up vector is always 1
- nup[2] = 0; // z component of up vector is always 0
-
- nl[0] = at.mV[0];
- nl[1] = 0; // y component of left vector is always zero, this was up[0]
- nl[2] = -1 * left.mV[0];
-
- npos[2] = pos.mdV[2] * -1.0;
- npos[1] = pos.mdV[1];
- npos[0] = pos.mdV[0];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-#else
- // This is the compose of the two transforms (at least, that's what I'm trying for)
- nat[0] = at.mV[VX];
- nat[1] = 0; // y component of at vector is always 0, this was up[2]
- nat[2] = -1 * up.mV[VZ];
-
- // We override whatever the application gives us
- nup[0] = 0; // x component of up vector is always 0
- nup[1] = 1; // y component of up vector is always 1
- nup[2] = 0; // z component of up vector is always 0
-
- nl[0] = left.mV[VX];
- nl[1] = 0; // y component of left vector is always zero, this was up[0]
- nl[2] = -1 * left.mV[VY];
-
- npos[0] = pos.mdV[VX];
- npos[1] = pos.mdV[VZ];
- npos[2] = pos.mdV[VY] * -1.0;
-
- nvel[0] = vel.mV[VX];
- nvel[1] = vel.mV[VZ];
- nvel[2] = vel.mV[VY];
-
- for(int i=0;i<3;++i) {
- at.mV[i] = nat[i];
- up.mV[i] = nup[i];
- left.mV[i] = nl[i];
- pos.mdV[i] = npos[i];
- }
-
-#endif
-}
-
-void LLVivoxVoiceClient::setHidden(bool hidden)
-{
- mHidden = hidden;
-
- if (mHidden && inSpatialChannel())
- {
- // get out of the channel entirely
- leaveAudioSession();
- }
- else
- {
- sendPositionAndVolumeUpdate();
- }
-}
-
-void LLVivoxVoiceClient::sendPositionAndVolumeUpdate(void)
-{
- std::ostringstream stream;
-
- if (mSpatialCoordsDirty && inSpatialChannel())
- {
- LLVector3 l, u, a, vel;
- LLVector3d pos;
-
- mSpatialCoordsDirty = false;
-
- // Always send both speaker and listener positions together.
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Set3DPosition.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>";
-
- stream << "<SpeakerPosition>";
-
- LLMatrix3 avatarRot = mAvatarRot.getMatrix3();
-
-// LL_DEBUGS("Voice") << "Sending speaker position " << mAvatarPosition << LL_ENDL;
- l = avatarRot.getLeftRow();
- u = avatarRot.getUpRow();
- a = avatarRot.getFwdRow();
-
- pos = mAvatarPosition;
- vel = mAvatarVelocity;
-
- // SLIM SDK: the old SDK was doing a transform on the passed coordinates that the new one doesn't do anymore.
- // The old transform is replicated by this function.
- oldSDKTransform(l, u, a, pos, vel);
-
- if (mHidden)
- {
- for (int i=0;i<3;++i)
- {
- pos.mdV[i] = VX_NULL_POSITION;
- }
- }
-
- stream
- << "<Position>"
- << "<X>" << pos.mdV[VX] << "</X>"
- << "<Y>" << pos.mdV[VY] << "</Y>"
- << "<Z>" << pos.mdV[VZ] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << vel.mV[VX] << "</X>"
- << "<Y>" << vel.mV[VY] << "</Y>"
- << "<Z>" << vel.mV[VZ] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << a.mV[VX] << "</X>"
- << "<Y>" << a.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << u.mV[VX] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << u.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VX] << "</X>"
- << "<Y>" << l.mV [VY] << "</Y>"
- << "<Z>" << l.mV [VZ] << "</Z>"
- << "</LeftOrientation>"
- ;
-
- stream << "</SpeakerPosition>";
-
- stream << "<ListenerPosition>";
-
- LLVector3d earPosition;
- LLVector3 earVelocity;
- LLMatrix3 earRot;
-
- switch(mEarLocation)
- {
- case earLocCamera:
- default:
- earPosition = mCameraPosition;
- earVelocity = mCameraVelocity;
- earRot = mCameraRot;
- break;
-
- case earLocAvatar:
- earPosition = mAvatarPosition;
- earVelocity = mAvatarVelocity;
- earRot = avatarRot;
- break;
-
- case earLocMixed:
- earPosition = mAvatarPosition;
- earVelocity = mAvatarVelocity;
- earRot = mCameraRot;
- break;
- }
-
- l = earRot.getLeftRow();
- u = earRot.getUpRow();
- a = earRot.getFwdRow();
-
- pos = earPosition;
- vel = earVelocity;
-
-
- oldSDKTransform(l, u, a, pos, vel);
-
- if (mHidden)
- {
- for (int i=0;i<3;++i)
- {
- pos.mdV[i] = VX_NULL_POSITION;
- }
- }
-
- stream
- << "<Position>"
- << "<X>" << pos.mdV[VX] << "</X>"
- << "<Y>" << pos.mdV[VY] << "</Y>"
- << "<Z>" << pos.mdV[VZ] << "</Z>"
- << "</Position>"
- << "<Velocity>"
- << "<X>" << vel.mV[VX] << "</X>"
- << "<Y>" << vel.mV[VY] << "</Y>"
- << "<Z>" << vel.mV[VZ] << "</Z>"
- << "</Velocity>"
- << "<AtOrientation>"
- << "<X>" << a.mV[VX] << "</X>"
- << "<Y>" << a.mV[VY] << "</Y>"
- << "<Z>" << a.mV[VZ] << "</Z>"
- << "</AtOrientation>"
- << "<UpOrientation>"
- << "<X>" << u.mV[VX] << "</X>"
- << "<Y>" << u.mV[VY] << "</Y>"
- << "<Z>" << u.mV[VZ] << "</Z>"
- << "</UpOrientation>"
- << "<LeftOrientation>"
- << "<X>" << l.mV [VX] << "</X>"
- << "<Y>" << l.mV [VY] << "</Y>"
- << "<Z>" << l.mV [VZ] << "</Z>"
- << "</LeftOrientation>"
- ;
-
- stream << "</ListenerPosition>";
-
- stream << "<ReqDispositionType>1</ReqDispositionType>"; //do not generate responses for update requests
- stream << "</Request>\n\n\n";
- }
-
- if(mAudioSession && (mAudioSession->mVolumeDirty || mAudioSession->mMuteDirty))
- {
- participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
-
- mAudioSession->mVolumeDirty = false;
- mAudioSession->mMuteDirty = false;
-
- for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
- {
- participantStatePtr_t p(iter->second);
-
- if(p->mVolumeDirty)
- {
- // Can't set volume/mute for yourself
- if(!p->mIsSelf)
- {
- // scale from the range 0.0-1.0 to vivox volume in the range 0-100
- S32 volume = ll_round(p->mVolume / VOLUME_SCALE_VIVOX);
- bool mute = p->mOnMuteList;
-
- if(mute)
- {
- // SetParticipantMuteForMe doesn't work in p2p sessions.
- // If we want the user to be muted, set their volume to 0 as well.
- // This isn't perfect, but it will at least reduce their volume to a minimum.
- volume = 0;
- // Mark the current volume level as set to prevent incoming events
- // changing it to 0, so that we can return to it when unmuting.
- p->mVolumeSet = true;
- }
-
- if(volume == 0)
- {
- mute = true;
- }
-
- LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL;
-
- // SLIM SDK: Send both volume and mute commands.
-
- // Send a "volume for me" command for the user.
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantVolumeForMe.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"
- << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
- << "<Volume>" << volume << "</Volume>"
- << "</Request>\n\n\n";
-
- if(!mAudioSession->mIsP2P)
- {
- // Send a "mute for me" command for the user
- // Doesn't work in P2P sessions
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantMuteForMe.1\">"
- << "<SessionHandle>" << getAudioSessionHandle() << "</SessionHandle>"
- << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
- << "<Mute>" << (mute?"1":"0") << "</Mute>"
- << "<Scope>Audio</Scope>"
- << "</Request>\n\n\n";
- }
- }
-
- p->mVolumeDirty = false;
- }
- }
- }
-
- std::string update(stream.str());
- if(!update.empty())
- {
- LL_DEBUGS("VoiceUpdate") << "sending update " << update << LL_ENDL;
- writeString(update);
- }
-
-}
-
-void LLVivoxVoiceClient::buildSetCaptureDevice(std::ostringstream &stream)
-{
- if(mCaptureDeviceDirty)
- {
- LL_DEBUGS("Voice") << "Setting input device = \"" << mCaptureDevice << "\"" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetCaptureDevice.1\">"
- << "<CaptureDeviceSpecifier>" << mCaptureDevice << "</CaptureDeviceSpecifier>"
- << "</Request>"
- << "\n\n\n";
-
- mCaptureDeviceDirty = false;
- }
-}
-
-void LLVivoxVoiceClient::buildSetRenderDevice(std::ostringstream &stream)
-{
- if(mRenderDeviceDirty)
- {
- LL_DEBUGS("Voice") << "Setting output device = \"" << mRenderDevice << "\"" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetRenderDevice.1\">"
- << "<RenderDeviceSpecifier>" << mRenderDevice << "</RenderDeviceSpecifier>"
- << "</Request>"
- << "\n\n\n";
- mRenderDeviceDirty = false;
- }
-}
-
-void LLVivoxVoiceClient::sendLocalAudioUpdates()
-{
- // Check all of the dirty states and then send messages to those needing to be changed.
- // Tuningmode hands its own mute settings.
- std::ostringstream stream;
-
- if (mMuteMicDirty && !mTuningMode)
- {
- mMuteMicDirty = false;
-
- // Send a local mute command.
-
- LL_INFOS("Voice") << "Sending MuteLocalMic command with parameter " << (mMuteMic ? "true" : "false") << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>" << (mMuteMic ? "true" : "false") << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if (mSpeakerMuteDirty && !mTuningMode)
- {
- const char *muteval = ((mSpeakerVolume <= scale_speaker_volume(0)) ? "true" : "false");
-
- mSpeakerMuteDirty = false;
-
- LL_INFOS("Voice") << "Setting speaker mute to " << muteval << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalSpeaker.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>" << muteval << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if (mSpeakerVolumeDirty)
- {
- mSpeakerVolumeDirty = false;
-
- LL_INFOS("Voice") << "Setting speaker volume to " << mSpeakerVolume << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalSpeakerVolume.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>" << mSpeakerVolume << "</Value>"
- << "</Request>\n\n\n";
-
- }
-
- if (mMicVolumeDirty)
- {
- mMicVolumeDirty = false;
-
- LL_INFOS("Voice") << "Setting mic volume to " << mMicVolume << LL_ENDL;
-
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalMicVolume.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>" << mMicVolume << "</Value>"
- << "</Request>\n\n\n";
- }
-
-
- if (!stream.str().empty())
- {
- writeString(stream.str());
- }
-}
-
-/**
- * Because of the recurring voice cutout issues (SL-15072) we are going to try
- * to disable the automatic VAD (Voice Activity Detection) and set the associated
- * parameters directly. We will expose them via Debug Settings and that should
- * let us iterate on a collection of values that work for us. Hopefully!
- *
- * From the VIVOX Docs:
- *
- * VadAuto: A flag indicating if the automatic VAD is enabled (1) or disabled (0)
- *
- * VadHangover: The time (in milliseconds) that it takes
- * for the VAD to switch back to silence from speech mode after the last speech
- * frame has been detected.
- *
- * VadNoiseFloor: A dimensionless value between 0 and
- * 20000 (default 576) that controls the maximum level at which the noise floor
- * may be set at by the VAD's noise tracking. Too low of a value will make noise
- * tracking ineffective (A value of 0 disables noise tracking and the VAD then
- * relies purely on the sensitivity property). Too high of a value will make
- * long speech classifiable as noise.
- *
- * VadSensitivity: A dimensionless value between 0 and
- * 100, indicating the 'sensitivity of the VAD'. Increasing this value corresponds
- * to decreasing the sensitivity of the VAD (i.e. '0' is most sensitive,
- * while 100 is 'least sensitive')
- */
-void LLVivoxVoiceClient::setupVADParams(unsigned int vad_auto,
- unsigned int vad_hangover,
- unsigned int vad_noise_floor,
- unsigned int vad_sensitivity)
-{
- std::ostringstream stream;
-
- LL_INFOS("Voice") << "Setting the automatic VAD to "
- << (vad_auto ? "True" : "False")
- << " and discrete values to"
- << " VadHangover = " << vad_hangover
- << ", VadSensitivity = " << vad_sensitivity
- << ", VadNoiseFloor = " << vad_noise_floor
- << LL_ENDL;
-
- // Create a request to set the VAD parameters:
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetVadProperties.1\">"
- << "<VadAuto>" << vad_auto << "</VadAuto>"
- << "<VadHangover>" << vad_hangover << "</VadHangover>"
- << "<VadSensitivity>" << vad_sensitivity << "</VadSensitivity>"
- << "<VadNoiseFloor>" << vad_noise_floor << "</VadNoiseFloor>"
- << "</Request>\n\n\n";
-
- if (!stream.str().empty())
- {
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::onVADSettingsChange()
-{
- // pick up the VAD variables (one of which was changed)
- unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto");
- unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover");
- unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor");
- unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity");
-
- // build a VAD params change request and send it to SLVoice
- setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity);
-}
-
-/////////////////////////////
-// Response/Event handlers
-
-void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID)
-{
- LLSD result = LLSD::emptyMap();
-
- if(statusCode == 0)
- {
- // Connector created, move forward.
- if (connectorHandle == LLVivoxSecurity::getInstance()->connectorHandle())
- {
- LL_INFOS("Voice") << "Voice connector succeeded, Vivox SDK version is " << versionID << " connector handle " << connectorHandle << LL_ENDL;
- mVoiceVersion.serverVersion = versionID;
- mConnectorEstablished = true;
- mTerminateDaemon = false;
-
- result["connector"] = LLSD::Boolean(true);
- }
- else
- {
- // This shouldn't happen - we are somehow out of sync with SLVoice
- // or possibly there are two things trying to run SLVoice at once
- // or someone is trying to hack into it.
- LL_WARNS("Voice") << "Connector returned wrong handle "
- << "(" << connectorHandle << ")"
- << " expected (" << LLVivoxSecurity::getInstance()->connectorHandle() << ")"
- << LL_ENDL;
- result["connector"] = LLSD::Boolean(false);
- // Give up.
- mTerminateDaemon = true;
- }
- }
- else if (statusCode == 10028) // web request timeout prior to login
- {
- // this is usually fatal, but a long timeout might work
- result["connector"] = LLSD::Boolean(false);
- result["retry"] = LLSD::Real(CONNECT_ATTEMPT_TIMEOUT);
-
- LL_WARNS("Voice") << "Voice connection failed" << LL_ENDL;
- }
- else if (statusCode == 10006) // name resolution failure - a shorter retry may work
- {
- // some networks have slower DNS, but a short timeout might let it catch up
- result["connector"] = LLSD::Boolean(false);
- result["retry"] = LLSD::Real(CONNECT_DNS_TIMEOUT);
-
- LL_WARNS("Voice") << "Voice connection DNS lookup failed" << LL_ENDL;
- }
- else // unknown failure - give up
- {
- LL_WARNS("Voice") << "Voice connection failure ("<< statusCode << "): " << statusString << LL_ENDL;
- mTerminateDaemon = true;
- result["connector"] = LLSD::Boolean(false);
- }
-
- mVivoxPump.post(result);
-}
-
-void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases)
-{
- LLSD result = LLSD::emptyMap();
-
- LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL;
-
- // Status code of 20200 means "bad password". We may want to special-case that at some point.
-
- if ( statusCode == HTTP_UNAUTHORIZED )
- {
- // Login failure which is probably caused by the delay after a user's password being updated.
- LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
- result["login"] = LLSD::String("retry");
- }
- else if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
- result["login"] = LLSD::String("failed");
- }
- else
- {
- // Login succeeded, move forward.
- mAccountLoggedIn = true;
- mNumberOfAliases = numberOfAliases;
- result["login"] = LLSD::String("response_ok");
- }
-
- mVivoxPump.post(result);
-
-}
-
-void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
-{
- sessionStatePtr_t session(findSessionBeingCreatedByURI(requestId));
-
- if(session)
- {
- session->mCreateInProgress = false;
- }
-
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Session.Create response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- {
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle))
- ("session", "failed")
- ("reason", LLSD::Integer(statusCode)));
-
- mVivoxPump.post(vivoxevent);
- }
- else
- {
- reapSession(session);
- }
- }
- }
- else
- {
- LL_INFOS("Voice") << "Session.Create response received (success), session handle is " << sessionHandle << LL_ENDL;
- if(session)
- {
- setSessionHandle(session, sessionHandle);
- }
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle))
- ("session", "created"));
-
- mVivoxPump.post(vivoxevent);
- }
-}
-
-void LLVivoxVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
-{
- sessionStatePtr_t session(findSessionBeingCreatedByURI(requestId));
-
- if(session)
- {
- session->mCreateInProgress = false;
- }
-
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "SessionGroup.AddSession response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- {
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle))
- ("session", "failed"));
-
- mVivoxPump.post(vivoxevent);
- }
- else
- {
- reapSession(session);
- }
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "SessionGroup.AddSession response received (success), session handle is " << sessionHandle << LL_ENDL;
- if(session)
- {
- setSessionHandle(session, sessionHandle);
- }
-
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(sessionHandle))
- ("session", "added"));
-
- mVivoxPump.post(vivoxevent);
-
- }
-}
-
-void LLVivoxVoiceClient::sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString)
-{
- sessionStatePtr_t session(findSession(requestId));
- // 1026 is session already has media, somehow mediaconnect was called twice on the same session.
- // set the session info to reflect that the user is already connected.
- if (statusCode == 1026)
- {
- session->mVoiceActive = true;
- session->mMediaConnectInProgress = false;
- session->mMediaStreamState = streamStateConnected;
- //session->mTextStreamState = streamStateConnected;
- session->mErrorStatusCode = 0;
- }
- else if (statusCode != 0)
- {
- LL_WARNS("Voice") << "Session.Connect response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if (session)
- {
- session->mMediaConnectInProgress = false;
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Session.Connect response received (success)" << LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::logoutResponse(int statusCode, std::string &statusString)
-{
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL;
- // Should this ever fail? do we care if it does?
- }
- LLSD vivoxevent(LLSDMap("logout", LLSD::Boolean(true)));
-
- mVivoxPump.post(vivoxevent);
-}
-
-void LLVivoxVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString)
-{
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Connector.InitiateShutdown response failure: " << statusString << LL_ENDL;
- // Should this ever fail? do we care if it does?
- }
-
- sConnected = false;
- mShutdownComplete = true;
-
- LLSD vivoxevent(LLSDMap("connector", LLSD::Boolean(false)));
-
- mVivoxPump.post(vivoxevent);
-}
-
-void LLVivoxVoiceClient::sessionAddedEvent(
- std::string &uriString,
- std::string &alias,
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- bool isChannel,
- bool incoming,
- std::string &nameString,
- std::string &applicationString)
-{
- sessionStatePtr_t session;
-
- LL_INFOS("Voice") << "session " << uriString << ", alias " << alias << ", name " << nameString << " handle " << sessionHandle << LL_ENDL;
-
- session = addSession(uriString, sessionHandle);
- if(session)
- {
- session->mGroupHandle = sessionGroupHandle;
- session->mIsChannel = isChannel;
- session->mIncoming = incoming;
- session->mAlias = alias;
-
- // Generate a caller UUID -- don't need to do this for channels
- if(!session->mIsChannel)
- {
- if(IDFromName(session->mSIPURI, session->mCallerID))
- {
- // Normal URI(base64-encoded UUID)
- }
- else if(!session->mAlias.empty() && IDFromName(session->mAlias, session->mCallerID))
- {
- // Wrong URI, but an alias is available. Stash the incoming URI as an alternate
- session->mAlternateSIPURI = session->mSIPURI;
-
- // and generate a proper URI from the ID.
- setSessionURI(session, sipURIFromID(session->mCallerID));
- }
- else
- {
- LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL;
- session->mCallerID.generate(session->mSIPURI);
- session->mSynthesizedCallerID = true;
-
- // Can't look up the name in this case -- we have to extract it from the URI.
- std::string namePortion = nameFromsipURI(session->mSIPURI);
- if(namePortion.empty())
- {
- // Didn't seem to be a SIP URI, just use the whole provided name.
- namePortion = nameString;
- }
-
- // Some incoming names may be separated with an underscore instead of a space. Fix this.
- LLStringUtil::replaceChar(namePortion, '_', ' ');
-
- // Act like we just finished resolving the name (this stores it in all the right places)
- avatarNameResolved(session->mCallerID, namePortion);
- }
-
- LL_INFOS("Voice") << "caller ID: " << session->mCallerID << LL_ENDL;
-
- if(!session->mSynthesizedCallerID)
- {
- // If we got here, we don't have a proper name. Initiate a lookup.
- lookupName(session->mCallerID);
- }
- }
- }
-}
-
-void LLVivoxVoiceClient::sessionGroupAddedEvent(std::string &sessionGroupHandle)
-{
- LL_DEBUGS("Voice") << "handle " << sessionGroupHandle << LL_ENDL;
-
-#if USE_SESSION_GROUPS
- if(mMainSessionGroupHandle.empty())
- {
- // This is the first (i.e. "main") session group. Save its handle.
- mMainSessionGroupHandle = sessionGroupHandle;
- }
- else
- {
- LL_DEBUGS("Voice") << "Already had a session group handle " << mMainSessionGroupHandle << LL_ENDL;
- }
-#endif
-}
-
-void LLVivoxVoiceClient::joinedAudioSession(const sessionStatePtr_t &session)
-{
- LL_DEBUGS("Voice") << "Joined Audio Session" << LL_ENDL;
- if(mAudioSession != session)
- {
- sessionStatePtr_t oldSession = mAudioSession;
-
- mAudioSession = session;
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
- }
-
- // This is the session we're joining.
- if(mIsJoiningSession)
- {
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle))
- ("session", "joined"));
-
- mVivoxPump.post(vivoxevent);
-
- // Add the current user as a participant here.
- participantStatePtr_t participant(session->addParticipant(sipURIFromName(mAccountName)));
- if(participant)
- {
- participant->mIsSelf = true;
- lookupName(participant->mAvatarID);
-
- LL_INFOS("Voice") << "added self as participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
- }
-
- if(!session->mIsChannel)
- {
- // this is a p2p session. Make sure the other end is added as a participant.
- participantStatePtr_t participant(session->addParticipant(session->mSIPURI));
- if(participant)
- {
- if(participant->mAvatarIDValid)
- {
- lookupName(participant->mAvatarID);
- }
- else if(!session->mName.empty())
- {
- participant->mDisplayName = session->mName;
- avatarNameResolved(participant->mAvatarID, session->mName);
- }
-
- // TODO: Question: Do we need to set up mAvatarID/mAvatarIDValid here?
- LL_INFOS("Voice") << "added caller as participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
- }
- }
- }
-}
-
-void LLVivoxVoiceClient::sessionRemovedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle)
-{
- LL_INFOS("Voice") << "handle " << sessionHandle << LL_ENDL;
-
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- leftAudioSession(session);
-
- // This message invalidates the session's handle. Set it to empty.
- clearSessionHandle(session);
-
- // This also means that the session's session group is now empty.
- // Terminate the session group so it doesn't leak.
- sessionGroupTerminateSendMessage(session);
-
- // Reset the media state (we now have no info)
- session->mMediaStreamState = streamStateUnknown;
- //session->mTextStreamState = streamStateUnknown;
-
- // Conditionally delete the session
- reapSession(session);
- }
- else
- {
- // Already reaped this session.
- LL_DEBUGS("Voice") << "unknown session " << sessionHandle << " removed" << LL_ENDL;
- }
-
-}
-
-void LLVivoxVoiceClient::reapSession(const sessionStatePtr_t &session)
-{
- if(session)
- {
-
- if(session->mCreateInProgress)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (create in progress)" << LL_ENDL;
- }
- else if(session->mMediaConnectInProgress)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (connect in progress)" << LL_ENDL;
- }
- else if(session == mAudioSession)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the current session)" << LL_ENDL;
- }
- else if(session == mNextAudioSession)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the next session)" << LL_ENDL;
- }
- else
- {
- // We don't have a reason to keep tracking this session, so just delete it.
- LL_DEBUGS("Voice") << "deleting session " << session->mSIPURI << LL_ENDL;
- deleteSession(session);
- }
- }
- else
- {
-// LL_DEBUGS("Voice") << "session is NULL" << LL_ENDL;
- }
-}
-
-// Returns true if the session seems to indicate we've moved to a region on a different voice server
-bool LLVivoxVoiceClient::sessionNeedsRelog(const sessionStatePtr_t &session)
-{
- bool result = false;
-
- if(session)
- {
- // Only make this check for spatial channels (so it won't happen for group or p2p calls)
- if(session->mIsSpatial)
- {
- std::string::size_type atsign;
-
- atsign = session->mSIPURI.find("@");
-
- if(atsign != std::string::npos)
- {
- std::string urihost = session->mSIPURI.substr(atsign + 1);
- if(stricmp(urihost.c_str(), mVoiceSIPURIHostName.c_str()))
- {
- // The hostname in this URI is different from what we expect. This probably means we need to relog.
-
- // We could make a ProvisionVoiceAccountRequest and compare the result with the current values of
- // mVoiceSIPURIHostName and mVoiceAccountServerURI to be really sure, but this is a pretty good indicator.
-
- result = true;
- }
- }
- }
- }
-
- return result;
-}
-
-void LLVivoxVoiceClient::leftAudioSession(const sessionStatePtr_t &session)
-{
- if (mAudioSession == session)
- {
- LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle))
- ("session", "removed"));
-
- mVivoxPump.post(vivoxevent);
- }
-}
-
-void LLVivoxVoiceClient::accountLoginStateChangeEvent(
- std::string &accountHandle,
- int statusCode,
- std::string &statusString,
- int state)
-{
- LLSD levent = LLSD::emptyMap();
-
- /*
- According to Mike S., status codes for this event are:
- login_state_logged_out=0,
- login_state_logged_in = 1,
- login_state_logging_in = 2,
- login_state_logging_out = 3,
- login_state_resetting = 4,
- login_state_error=100
- */
-
- LL_DEBUGS("Voice") << "state change event: " << state << LL_ENDL;
- switch(state)
- {
- case 1:
- levent["login"] = LLSD::String("account_login");
-
- mVivoxPump.post(levent);
- break;
- case 2:
- break;
-
- case 3:
- levent["login"] = LLSD::String("account_loggingOut");
-
- mVivoxPump.post(levent);
- break;
-
- case 4:
- break;
-
- case 100:
- LL_WARNS("Voice") << "account state event error" << LL_ENDL;
- break;
-
- case 0:
- levent["login"] = LLSD::String("account_logout");
-
- mVivoxPump.post(levent);
- break;
-
- default:
- //Used to be a commented out warning
- LL_WARNS("Voice") << "unknown account state event: " << state << LL_ENDL;
- break;
- }
-}
-
-void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType)
-{
- LLSD result;
-
- if (mediaCompletionType == "AuxBufferAudioCapture")
- {
- mCaptureBufferRecording = false;
- result["recplay"] = "end";
- }
- else if (mediaCompletionType == "AuxBufferAudioRender")
- {
- // Ignore all but the last stop event
- if (--mPlayRequestCount <= 0)
- {
- mCaptureBufferPlaying = false;
- result["recplay"] = "end";
-// result["recplay"] = "done";
- }
- }
- else
- {
- LL_WARNS("Voice") << "Unknown MediaCompletionType: " << mediaCompletionType << LL_ENDL;
- }
-
- if (!result.isUndefined())
- mVivoxPump.post(result);
-}
-
-void LLVivoxVoiceClient::mediaStreamUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- int statusCode,
- std::string &statusString,
- int state,
- bool incoming)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
-
- LL_DEBUGS("Voice") << "session " << sessionHandle << ", status code " << statusCode << ", string \"" << statusString << "\"" << LL_ENDL;
-
- if(session)
- {
- // We know about this session
-
- // Save the state for later use
- session->mMediaStreamState = state;
-
- switch(statusCode)
- {
- case 0:
- case HTTP_OK:
- // generic success
- // Don't change the saved error code (it may have been set elsewhere)
- break;
- default:
- // save the status code for later
- session->mErrorStatusCode = statusCode;
- break;
- }
-
- switch(state)
- {
- case streamStateDisconnecting:
- case streamStateIdle:
- // Standard "left audio session", Vivox state 'disconnected'
- session->mVoiceActive = false;
- session->mMediaConnectInProgress = false;
- leftAudioSession(session);
- break;
-
- case streamStateConnected:
- session->mVoiceActive = true;
- session->mMediaConnectInProgress = false;
- joinedAudioSession(session);
- case streamStateConnecting: // do nothing, but prevents a warning getting into the logs.
- break;
-
- case streamStateRinging:
- if(incoming)
- {
- // Send the voice chat invite to the GUI layer
- // TODO: Question: Should we correlate with the mute list here?
- session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID);
- session->mVoiceInvitePending = true;
- if(session->mName.empty())
- {
- lookupName(session->mCallerID);
- }
- else
- {
- // Act like we just finished resolving the name
- avatarNameResolved(session->mCallerID, session->mName);
- }
- }
- break;
-
- default:
- LL_WARNS("Voice") << "unknown state " << state << LL_ENDL;
- break;
-
- }
-
- }
- else
- {
- // session disconnectintg and disconnected events arriving after we have already left the session.
- LL_DEBUGS("Voice") << "session " << sessionHandle << " not found"<< LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::participantAddedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- std::string &nameString,
- std::string &displayNameString,
- int participantType)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- participantStatePtr_t participant(session->addParticipant(uriString));
- if(participant)
- {
- participant->mAccountName = nameString;
-
- LL_DEBUGS("Voice") << "added participant \"" << participant->mAccountName
- << "\" (" << participant->mAvatarID << ")"<< LL_ENDL;
-
- if(participant->mAvatarIDValid)
- {
- // Initiate a lookup
- lookupName(participant->mAvatarID);
- }
- else
- {
- // If we don't have a valid avatar UUID, we need to fill in the display name to make the active speakers floater work.
- std::string namePortion = nameFromsipURI(uriString);
- if(namePortion.empty())
- {
- // Problem with the SIP URI, fall back to the display name
- namePortion = displayNameString;
- }
- if(namePortion.empty())
- {
- // Problems with both of the above, fall back to the account name
- namePortion = nameString;
- }
-
- // Set the display name (which is a hint to the active speakers window not to do its own lookup)
- participant->mDisplayName = namePortion;
- avatarNameResolved(participant->mAvatarID, namePortion);
- }
- }
- }
-}
-
-void LLVivoxVoiceClient::participantRemovedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- std::string &nameString)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- participantStatePtr_t participant(session->findParticipant(uriString));
- if(participant)
- {
- session->removeParticipant(participant);
- }
- else
- {
- LL_DEBUGS("Voice") << "unknown participant " << uriString << LL_ENDL;
- }
- }
- else
- {
- // a late arriving event on a session we have already left.
- LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
- }
-}
-
-
-void LLVivoxVoiceClient::participantUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- bool isModeratorMuted,
- bool isSpeaking,
- int volume,
- F32 energy)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- participantStatePtr_t participant(session->findParticipant(uriString));
-
- if(participant)
- {
- //LL_INFOS("Voice") << "Participant Update for " << participant->mDisplayName << LL_ENDL;
-
- participant->mIsSpeaking = isSpeaking;
- participant->mIsModeratorMuted = isModeratorMuted;
-
- // SLIM SDK: convert range: ensure that energy is set to zero if is_speaking is false
- if (isSpeaking)
- {
- participant->mSpeakingTimeout.reset();
- participant->mPower = energy;
- }
- else
- {
- participant->mPower = 0.0f;
- }
-
- // Ignore incoming volume level if it has been explicitly set, or there
- // is a volume or mute change pending.
- if ( !participant->mVolumeSet && !participant->mVolumeDirty)
- {
- participant->mVolume = (F32)volume * VOLUME_SCALE_VIVOX;
- }
-
- // *HACK: mantipov: added while working on EXT-3544
- /*
- Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE
- LLViewerChatterBoxSessionAgentListUpdates::post() sometimes AFTER.
-
- participantUpdatedEvent updates voice participant state in particular participantState::mIsModeratorMuted
- Originally we wanted to update session Speaker Manager to fire LLSpeakerVoiceModerationEvent to fix the EXT-3544 bug.
- Calling of the LLSpeakerMgr::update() method was added into LLIMMgr::processAgentListUpdates.
-
- But in case participantUpdatedEvent() is called after LLViewerChatterBoxSessionAgentListUpdates::post()
- voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager
- and event is not fired.
-
- So, we have to call LLSpeakerMgr::update() here.
- */
- LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel();
-
- // ignore session ID of local chat
- if (voice_cnl && voice_cnl->getSessionID().notNull())
- {
- LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(voice_cnl->getSessionID());
- if (speaker_manager)
- {
- speaker_manager->update(true);
-
- // also initialize voice moderate_mode depend on Agent's participant. See EXT-6937.
- // *TODO: remove once a way to request the current voice channel moderation mode is implemented.
- if (gAgent.getID() == participant->mAvatarID)
- {
- speaker_manager->initVoiceModerateMode();
- }
- }
- }
- }
- else
- {
- LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::messageEvent(
- std::string &sessionHandle,
- std::string &uriString,
- std::string &alias,
- std::string &messageHeader,
- std::string &messageBody,
- std::string &applicationString)
-{
- LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL;
-// LL_DEBUGS("Voice") << " header " << messageHeader << ", body: \n" << messageBody << LL_ENDL;
-
- LL_INFOS("Voice") << "Vivox raw message:" << std::endl << messageBody << LL_ENDL;
-
- if(messageHeader.find(HTTP_CONTENT_TEXT_HTML) != std::string::npos)
- {
- std::string message;
-
- {
- const std::string startMarker = "<body";
- const std::string startMarker2 = ">";
- const std::string endMarker = "</body>";
- const std::string startSpan = "<span";
- const std::string endSpan = "</span>";
- std::string::size_type start;
- std::string::size_type end;
-
- // Default to displaying the raw string, so the message gets through.
- message = messageBody;
-
- // Find the actual message text within the XML fragment
- start = messageBody.find(startMarker);
- start = messageBody.find(startMarker2, start);
- end = messageBody.find(endMarker);
-
- if(start != std::string::npos)
- {
- start += startMarker2.size();
-
- if(end != std::string::npos)
- end -= start;
-
- message.assign(messageBody, start, end);
- }
- else
- {
- // Didn't find a <body>, try looking for a <span> instead.
- start = messageBody.find(startSpan);
- start = messageBody.find(startMarker2, start);
- end = messageBody.find(endSpan);
-
- if(start != std::string::npos)
- {
- start += startMarker2.size();
-
- if(end != std::string::npos)
- end -= start;
-
- message.assign(messageBody, start, end);
- }
- }
- }
-
-// LL_DEBUGS("Voice") << " raw message = \n" << message << LL_ENDL;
-
- // strip formatting tags
- {
- std::string::size_type start;
- std::string::size_type end;
-
- while((start = message.find('<')) != std::string::npos)
- {
- if((end = message.find('>', start + 1)) != std::string::npos)
- {
- // Strip out the tag
- message.erase(start, (end + 1) - start);
- }
- else
- {
- // Avoid an infinite loop
- break;
- }
- }
- }
-
- // Decode ampersand-escaped chars
- {
- std::string::size_type mark = 0;
-
- // The text may contain text encoded with &lt;, &gt;, and &amp;
- mark = 0;
- while((mark = message.find("&lt;", mark)) != std::string::npos)
- {
- message.replace(mark, 4, "<");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&gt;", mark)) != std::string::npos)
- {
- message.replace(mark, 4, ">");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&amp;", mark)) != std::string::npos)
- {
- message.replace(mark, 5, "&");
- mark += 1;
- }
- }
-
- // strip leading/trailing whitespace (since we always seem to get a couple newlines)
- LLStringUtil::trim(message);
-
-// LL_DEBUGS("Voice") << " stripped message = \n" << message << LL_ENDL;
-
- sessionStatePtr_t session(findSession(sessionHandle));
- if(session)
- {
- bool is_do_not_disturb = gAgent.isDoNotDisturb();
- bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat);
- bool is_linden = LLMuteList::isLinden(session->mName);
- LLChat chat;
-
- chat.mMuted = is_muted && !is_linden;
-
- if(!chat.mMuted)
- {
- chat.mFromID = session->mCallerID;
- chat.mFromName = session->mName;
- chat.mSourceType = CHAT_SOURCE_AGENT;
-
- if(is_do_not_disturb && !is_linden)
- {
- // TODO: Question: Return do not disturb mode response here? Or maybe when session is started instead?
- }
-
- LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL;
- LLIMMgr::getInstance()->addMessage(session->mIMSessionID,
- session->mCallerID,
- session->mName.c_str(),
- message.c_str(),
- false,
- LLStringUtil::null, // default arg
- IM_NOTHING_SPECIAL, // default arg
- 0, // default arg
- LLUUID::null, // default arg
- LLVector3::zero); // default arg
- }
- }
- }
-}
-
-void LLVivoxVoiceClient::sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
-
- if(session)
- {
- participantStatePtr_t participant(session->findParticipant(uriString));
- if(participant)
- {
- if (!stricmp(notificationType.c_str(), "Typing"))
- {
- // Other end started typing
- // TODO: The proper way to add a typing notification seems to be LLIMMgr::processIMTypingStart().
- // It requires some info for the message, which we don't have here.
- }
- else if (!stricmp(notificationType.c_str(), "NotTyping"))
- {
- // Other end stopped typing
- // TODO: The proper way to remove a typing notification seems to be LLIMMgr::processIMTypingStop().
- // It requires some info for the message, which we don't have here.
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown notification type " << notificationType << "for participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown session handle " << sessionHandle << LL_ENDL;
- }
-}
-
-void LLVivoxVoiceClient::voiceServiceConnectionStateChangedEvent(int statusCode, std::string &statusString, std::string &build_id)
-{
- // We don't generally need to process this. However, one occurence is when we first connect, and so it is the
- // earliest opportunity to learn what we're connected to.
- if (statusCode)
- {
- LL_WARNS("Voice") << "VoiceServiceConnectionStateChangedEvent statusCode: " << statusCode <<
- "statusString: " << statusString << LL_ENDL;
- return;
- }
- if (build_id.empty())
- {
- return;
- }
- mVoiceVersion.mBuildVersion = build_id;
-}
-
-void LLVivoxVoiceClient::auxAudioPropertiesEvent(F32 energy)
-{
- LL_DEBUGS("VoiceEnergy") << "got energy " << energy << LL_ENDL;
- mTuningEnergy = energy;
-}
-
-void LLVivoxVoiceClient::muteListChanged()
-{
- // The user's mute list has been updated. Go through the current participant list and sync it with the mute list.
- if(mAudioSession)
- {
- participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
-
- for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
- {
- participantStatePtr_t p(iter->second);
-
- // Check to see if this participant is on the mute list already
- if(p->updateMuteState())
- mAudioSession->mVolumeDirty = true;
- }
- }
-}
-
-/////////////////////////////
-// Managing list of participants
-LLVivoxVoiceClient::participantState::participantState(const std::string &uri) :
- mURI(uri),
- mPTT(false),
- mIsSpeaking(false),
- mIsModeratorMuted(false),
- mLastSpokeTimestamp(0.f),
- mPower(0.f),
- mVolume(LLVoiceClient::VOLUME_DEFAULT),
- mUserVolume(0),
- mOnMuteList(false),
- mVolumeSet(false),
- mVolumeDirty(false),
- mAvatarIDValid(false),
- mIsSelf(false)
-{
-}
-
-LLVivoxVoiceClient::participantStatePtr_t LLVivoxVoiceClient::sessionState::addParticipant(const std::string &uri)
-{
- participantStatePtr_t result;
- bool useAlternateURI = false;
-
- // Note: this is mostly the body of LLVivoxVoiceClient::sessionState::findParticipant(), but since we need to know if it
- // matched the alternate SIP URI (so we can add it properly), we need to reproduce it here.
- {
- participantMap::iterator iter = mParticipantsByURI.find(uri);
-
- if(iter == mParticipantsByURI.end())
- {
- if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
- {
- // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
- // Use mSIPURI instead, since it will be properly encoded.
- iter = mParticipantsByURI.find(mSIPURI);
- useAlternateURI = true;
- }
- }
-
- if(iter != mParticipantsByURI.end())
- {
- result = iter->second;
- }
- }
-
- if(!result)
- {
- // participant isn't already in one list or the other.
- result = std::make_shared<participantState>(useAlternateURI?mSIPURI:uri);
- mParticipantsByURI.insert(participantMap::value_type(result->mURI, result));
- mParticipantsChanged = true;
-
- // Try to do a reverse transform on the URI to get the GUID back.
- {
- LLUUID id;
- if(LLVivoxVoiceClient::getInstance()->IDFromName(result->mURI, id))
- {
- result->mAvatarIDValid = true;
- result->mAvatarID = id;
- }
- else
- {
- // Create a UUID by hashing the URI, but do NOT set mAvatarIDValid.
- // This indicates that the ID will not be in the name cache.
- result->mAvatarID.generate(uri);
- }
- }
-
- if(result->updateMuteState())
- {
- mMuteDirty = true;
- }
-
- mParticipantsByUUID.insert(participantUUIDMap::value_type(result->mAvatarID, result));
-
- if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume))
- {
- result->mVolumeDirty = true;
- mVolumeDirty = true;
- }
-
- LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL;
- }
-
- return result;
-}
-
-bool LLVivoxVoiceClient::participantState::updateMuteState()
-{
- bool result = false;
-
- bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat);
- if(mOnMuteList != isMuted)
- {
- mOnMuteList = isMuted;
- mVolumeDirty = true;
- result = true;
- }
- return result;
-}
-
-bool LLVivoxVoiceClient::participantState::isAvatar()
-{
- return mAvatarIDValid;
-}
-
-void LLVivoxVoiceClient::sessionState::removeParticipant(const LLVivoxVoiceClient::participantStatePtr_t &participant)
-{
- if(participant)
- {
- participantMap::iterator iter = mParticipantsByURI.find(participant->mURI);
- participantUUIDMap::iterator iter2 = mParticipantsByUUID.find(participant->mAvatarID);
-
- LL_DEBUGS("Voice") << "participant \"" << participant->mURI << "\" (" << participant->mAvatarID << ") removed." << LL_ENDL;
-
- if(iter == mParticipantsByURI.end())
- {
- LL_WARNS("Voice") << "Internal error: participant " << participant->mURI << " not in URI map" << LL_ENDL;
- }
- else if(iter2 == mParticipantsByUUID.end())
- {
- LL_WARNS("Voice") << "Internal error: participant ID " << participant->mAvatarID << " not in UUID map" << LL_ENDL;
- }
- else if(iter->second != iter2->second)
- {
- LL_WARNS("Voice") << "Internal error: participant mismatch!" << LL_ENDL;
- }
- else
- {
- mParticipantsByURI.erase(iter);
- mParticipantsByUUID.erase(iter2);
-
- mParticipantsChanged = true;
- }
- }
-}
-
-void LLVivoxVoiceClient::sessionState::removeAllParticipants()
-{
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
-
- while(!mParticipantsByURI.empty())
- {
- removeParticipant(mParticipantsByURI.begin()->second);
- }
-
- if(!mParticipantsByUUID.empty())
- {
- LL_WARNS("Voice") << "Internal error: empty URI map, non-empty UUID map" << LL_ENDL;
- }
-}
-
-/*static*/
-void LLVivoxVoiceClient::sessionState::VerifySessions()
-{
- std::set<wptr_t>::iterator it = mSession.begin();
- while (it != mSession.end())
- {
- if ((*it).expired())
- {
- LL_WARNS("Voice") << "Expired session found! removing" << LL_ENDL;
- it = mSession.erase(it);
- }
- else
- ++it;
- }
-}
-
-
-void LLVivoxVoiceClient::getParticipantList(std::set<LLUUID> &participants)
-{
- if(mProcessChannels && mAudioSession)
- {
- for(participantUUIDMap::iterator iter = mAudioSession->mParticipantsByUUID.begin();
- iter != mAudioSession->mParticipantsByUUID.end();
- iter++)
- {
- participants.insert(iter->first);
- }
- }
-}
-
-bool LLVivoxVoiceClient::isParticipant(const LLUUID &speaker_id)
-{
- if(mProcessChannels && mAudioSession)
- {
- return (mAudioSession->mParticipantsByUUID.find(speaker_id) != mAudioSession->mParticipantsByUUID.end());
- }
- return false;
-}
-
-
-LLVivoxVoiceClient::participantStatePtr_t LLVivoxVoiceClient::sessionState::findParticipant(const std::string &uri)
-{
- participantStatePtr_t result;
-
- participantMap::iterator iter = mParticipantsByURI.find(uri);
-
- if(iter == mParticipantsByURI.end())
- {
- if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
- {
- // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
- // Look up the other URI
- iter = mParticipantsByURI.find(mSIPURI);
- }
- }
-
- if(iter != mParticipantsByURI.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-LLVivoxVoiceClient::participantStatePtr_t LLVivoxVoiceClient::sessionState::findParticipantByID(const LLUUID& id)
-{
- participantStatePtr_t result;
- participantUUIDMap::iterator iter = mParticipantsByUUID.find(id);
-
- if(iter != mParticipantsByUUID.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-LLVivoxVoiceClient::participantStatePtr_t LLVivoxVoiceClient::findParticipantByID(const LLUUID& id)
-{
- participantStatePtr_t result;
-
- if(mAudioSession)
- {
- result = mAudioSession->findParticipantByID(id);
- }
-
- return result;
-}
-
-
-
-// Check for parcel boundary crossing
-bool LLVivoxVoiceClient::checkParcelChanged(bool update)
-{
- LLViewerRegion *region = gAgent.getRegion();
- LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-
- if(region && parcel)
- {
- S32 parcelLocalID = parcel->getLocalID();
- std::string regionName = region->getName();
-
- // LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL;
-
- // The region name starts out empty and gets filled in later.
- // Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes.
- // If either is empty, wait for the next time around.
- if(!regionName.empty())
- {
- if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
- {
- // We have changed parcels. Initiate a parcel channel lookup.
- if (update)
- {
- mCurrentParcelLocalID = parcelLocalID;
- mCurrentRegionName = regionName;
- }
- return true;
- }
- }
- }
- return false;
-}
-
-bool LLVivoxVoiceClient::switchChannel(
- std::string uri,
- bool spatial,
- bool no_reconnect,
- bool is_p2p,
- std::string hash)
-{
- bool needsSwitch = !mIsInChannel;
-
- if (mIsInChannel)
- {
- if (mSessionTerminateRequested)
- {
- // If a terminate has been requested, we need to compare against where the URI we're already headed to.
- if(mNextAudioSession)
- {
- if (mNextAudioSession->mSIPURI != uri)
- {
- needsSwitch = true;
- }
- }
- else
- {
- // mNextAudioSession is null -- this probably means we're on our way back to spatial.
- if(!uri.empty())
- {
- // We do want to process a switch in this case.
- needsSwitch = true;
- }
- }
- }
- else
- {
- // Otherwise, compare against the URI we're in now.
- if(mAudioSession)
- {
- if(mAudioSession->mSIPURI != uri)
- {
- needsSwitch = true;
- }
- }
- else
- {
- if(!uri.empty())
- {
- // mAudioSession is null -- it's not clear what case would cause this.
- // For now, log it as a warning and see if it ever crops up.
- LL_WARNS("Voice") << "No current audio session... Forcing switch" << LL_ENDL;
- needsSwitch = true;
- }
- }
- }
- }
-
- if(needsSwitch)
- {
- if(uri.empty())
- {
- // Leave any channel we may be in
- LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL;
-
- sessionStatePtr_t oldSession = mNextAudioSession;
- mNextAudioSession.reset();
-
- // The old session may now need to be deleted.
- reapSession(oldSession);
-
- // If voice was on, turn it off
- if (LLVoiceClient::getInstance()->getUserPTTState())
- {
- LLVoiceClient::getInstance()->setUserPTTState(false);
- }
-
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- }
- else
- {
- LL_DEBUGS("Voice") << "switching to channel " << uri << LL_ENDL;
-
- mNextAudioSession = addSession(uri);
- mNextAudioSession->mHash = hash;
- mNextAudioSession->mIsSpatial = spatial;
- mNextAudioSession->mReconnect = !no_reconnect;
- mNextAudioSession->mIsP2P = is_p2p;
- }
-
- if (mIsInChannel)
- {
- // If we're already in a channel, or if we're joining one, terminate
- // so we can rejoin with the new session data.
- sessionTerminate();
- }
- }
-
- return needsSwitch;
-}
-
-void LLVivoxVoiceClient::joinSession(const sessionStatePtr_t &session)
-{
- mNextAudioSession = session;
-
- if (mIsInChannel)
- {
- // If we're already in a channel, or if we're joining one, terminate
- // so we can rejoin with the new session data.
- sessionTerminate();
- }
-}
-
-void LLVivoxVoiceClient::setNonSpatialChannel(const LLSD& channelInfo, bool notify_on_first_join, bool hangup_on_last_leave)
-{
- switchChannel(channelInfo["channel_uri"].asString(), false, false, false, channelInfo["channel_credentials"].asString());
-}
-
-bool LLVivoxVoiceClient::setSpatialChannel(const LLSD& channelInfo)
-{
- mSpatialSessionURI = channelInfo["channel_uri"].asString();
- mSpatialSessionCredentials = channelInfo["channel_credentials"].asString();
- if (!mProcessChannels)
- {
- // we're not even processing channels (another provider is) so
- // save the credentials aside and exit
- return false;
- }
-
- LL_DEBUGS("Voice") << "got spatial channel uri: \"" << mSpatialSessionURI << "\"" << LL_ENDL;
-
- if((mIsInChannel && mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial)))
- {
- // User is in a non-spatial chat or joining a non-spatial chat. Don't switch channels.
- LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL;
- return false;
- }
- else
- {
- return switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
- }
-}
-
-void LLVivoxVoiceClient::callUser(const LLUUID &uuid)
-{
- std::string userURI = sipURIFromID(uuid);
- mProcessChannels = true;
-
- switchChannel(userURI, false, true, true);
-}
-
-void LLVivoxVoiceClient::hangup() { leaveChannel(); }
-
-
-LLVoiceP2PIncomingCallInterfacePtr LLVivoxVoiceClient::getIncomingCallInterface(const LLSD &voice_call_info)
-{
- return std::make_shared<LLVivoxVoiceP2PIncomingCall>(voice_call_info);
-}
-
-bool LLVivoxVoiceClient::answerInvite(const std::string &sessionHandle)
-{
- // this is only ever used to answer incoming p2p call invites.
-
- sessionStatePtr_t session(findSession(sessionHandle));
- if (session)
- {
- session->mIsSpatial = false;
- session->mReconnect = false;
- session->mIsP2P = true;
- mProcessChannels = true;
- joinSession(session);
- return true;
- }
-
- return false;
-}
-
-void LLVivoxVoiceClient::declineInvite(const std::string &sessionHandle)
-{
- sessionStatePtr_t session(findSession(sessionHandle));
- if (session)
- {
- sessionMediaDisconnectSendMessage(session);
- }
-}
-
-bool LLVivoxVoiceClient::isVoiceWorking() const
-{
-
- //Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758)
- // Condition with joining spatial num was added to take into account possible problems with connection to voice
- // server(EXT-4313). See bug descriptions and comments for MAX_NORMAL_JOINING_SPATIAL_NUM for more info.
- return (mSpatialJoiningNum < MAX_NORMAL_JOINING_SPATIAL_NUM) && mIsLoggedIn;
-}
-
-// Returns true if the indicated participant in the current audio session is really an SL avatar.
-// Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls.
-bool LLVivoxVoiceClient::isParticipantAvatar(const LLUUID &id)
-{
- bool result = true;
- sessionStatePtr_t session(findSession(id));
-
- if(session)
- {
- // this is a p2p session with the indicated caller, or the session with the specified UUID.
- if(session->mSynthesizedCallerID)
- result = false;
- }
- else
- {
- // Didn't find a matching session -- check the current audio session for a matching participant
- if(mAudioSession)
- {
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->isAvatar();
- }
- }
- }
-
- return result;
-}
-
-// Returns true if calling back the session URI after the session has closed is possible.
-// Currently this will be false only for PSTN P2P calls.
-bool LLVivoxVoiceClient::isSessionCallBackPossible(const LLUUID &session_id)
-{
- bool result = true;
- sessionStatePtr_t session(findSession(session_id));
-
- if(session != NULL)
- {
- result = session->isCallBackPossible();
- }
-
- return result;
-}
-
-// Returns true if the session can accept text IM's.
-// Currently this will be false only for PSTN P2P calls.
-bool LLVivoxVoiceClient::isSessionTextIMPossible(const LLUUID &session_id)
-{
- bool result = true;
- sessionStatePtr_t session(findSession(session_id));
-
- if(session != NULL)
- {
- result = session->isTextIMPossible();
- }
-
- return result;
-}
-
-void LLVivoxVoiceClient::leaveNonSpatialChannel()
-{
- LL_DEBUGS("Voice") << "Request to leave spacial channel." << LL_ENDL;
-
- // Make sure we don't rejoin the current session.
- sessionStatePtr_t oldNextSession(mNextAudioSession);
- mNextAudioSession.reset();
-
- // Most likely this will still be the current session at this point, but check it anyway.
- reapSession(oldNextSession);
-
- verifySessionState();
-
- sessionTerminate();
-}
-
-void LLVivoxVoiceClient::processChannels(bool process)
-{
- mCurrentParcelLocalID = -1;
- mCurrentRegionName.clear();
- mProcessChannels = process;
-}
-
-bool LLVivoxVoiceClient::isCurrentChannel(const LLSD &channelInfo)
-{
- if (!mProcessChannels
- || (channelInfo.has("voice_server_type") && channelInfo["voice_server_type"].asString() != VIVOX_VOICE_SERVER_TYPE)
- || mSessionTerminateRequested)
- {
- return false;
- }
- // favor the next audio session, as that's the one we're bringing up.
- sessionStatePtr_t session = mNextAudioSession;
- if (!session)
- {
- session = mAudioSession;
- }
- if (session)
- {
- if (!channelInfo["session_handle"].asString().empty())
- {
- return session->mHandle == channelInfo["session_handle"].asString();
- }
- return channelInfo["channel_uri"].asString() == session->mSIPURI;
- }
- return false;
-}
-
-bool LLVivoxVoiceClient::compareChannels(const LLSD& channelInfo1, const LLSD& channelInfo2)
-{
- return (!channelInfo1.has("voice_server_type") || (channelInfo1["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) &&
- (!channelInfo2.has("voice_server_type") || (channelInfo2["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) &&
- (channelInfo1["channel_uri"] == channelInfo2["channel_uri"]);
-}
-
-bool LLVivoxVoiceClient::inProximalChannel()
-{
- bool result = false;
-
- if (mIsInChannel && !mSessionTerminateRequested)
- {
- result = inSpatialChannel();
- }
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::sipURIFromID(const LLUUID &id) const
-{
- std::string result;
- result = "sip:";
- result += nameFromID(id);
- result += "@";
- result += mVoiceSIPURIHostName;
-
- return result;
-}
-
-LLSD LLVivoxVoiceClient::getP2PChannelInfoTemplate(const LLUUID& id) const
-{
- LLSD result;
- result["channel_uri"] = sipURIFromID(id);
- result["voice_server_type"] = VIVOX_VOICE_SERVER_TYPE;
- return result;
-}
-
-std::string LLVivoxVoiceClient::sipURIFromAvatar(LLVOAvatar *avatar)
-{
- std::string result;
- if(avatar)
- {
- result = "sip:";
- result += nameFromID(avatar->getID());
- result += "@";
- result += mVoiceSIPURIHostName;
- }
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::nameFromID(const LLUUID &uuid) const
-{
- std::string result;
-
- if (uuid.isNull()) {
- //VIVOX, the uuid emtpy look for the mURIString and return that instead.
- //result.assign(uuid.mURIStringName);
- LLStringUtil::replaceChar(result, '_', ' ');
- return result;
- }
- // Prepending this apparently prevents conflicts with reserved names inside the vivox code.
- result = "x";
-
- // Base64 encode and replace the pieces of base64 that are less compatible
- // with e-mail local-parts.
- // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet"
- result += LLBase64::encode(uuid.mData, UUID_BYTES);
- LLStringUtil::replaceChar(result, '+', '-');
- LLStringUtil::replaceChar(result, '/', '_');
-
- // If you need to transform a GUID to this form on the macOS command line, this will do so:
- // echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-')
-
- // The reverse transform can be done with:
- // echo 'x5mkTKmxDTuGnjWyC__WfMg==' |cut -b 2- -|tr '_-' '/+' |openssl base64 -d|xxd -p
-
- return result;
-}
-
-bool LLVivoxVoiceClient::IDFromName(const std::string inName, LLUUID &uuid)
-{
- bool result = false;
-
- // SLIM SDK: The "name" may actually be a SIP URI such as: "sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com"
- // If it is, convert to a bare name before doing the transform.
- std::string name = nameFromsipURI(inName);
-
- // Doesn't look like a SIP URI, assume it's an actual name.
- if(name.empty())
- name = inName;
-
- // This will only work if the name is of the proper form.
- // As an example, the account name for Monroe Linden (UUID 1673cfd3-8229-4445-8d92-ec3570e5e587) is:
- // "xFnPP04IpREWNkuw1cOXlhw=="
-
- if((name.size() == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '='))
- {
- // The name appears to have the right form.
-
- // Reverse the transforms done by nameFromID
- std::string temp = name;
- LLStringUtil::replaceChar(temp, '-', '+');
- LLStringUtil::replaceChar(temp, '_', '/');
-
- U8 rawuuid[UUID_BYTES + 1];
- int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1);
- if(len == UUID_BYTES)
- {
- // The decode succeeded. Stuff the bits into the result's UUID
- memcpy(uuid.mData, rawuuid, UUID_BYTES);
- result = true;
- }
- }
-
- if(!result)
- {
- // VIVOX: not a standard account name, just copy the URI name mURIString field
- // and hope for the best. bpj
- uuid.setNull(); // VIVOX, set the uuid field to nulls
- }
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::sipURIFromName(std::string &name)
-{
- std::string result;
- result = "sip:";
- result += name;
- result += "@";
- result += mVoiceSIPURIHostName;
-
-// LLStringUtil::toLower(result);
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::nameFromsipURI(const std::string &uri)
-{
- std::string result;
-
- std::string::size_type sipOffset, atOffset;
- sipOffset = uri.find("sip:");
- atOffset = uri.find("@");
- if((sipOffset != std::string::npos) && (atOffset != std::string::npos))
- {
- result = uri.substr(sipOffset + 4, atOffset - (sipOffset + 4));
- }
-
- return result;
-}
-
-bool LLVivoxVoiceClient::inSpatialChannel(void)
-{
- bool result = false;
-
- if(mAudioSession)
- {
- result = mAudioSession->mIsSpatial;
- }
-
- return result;
-}
-
-
-LLSD LLVivoxVoiceClient::getAudioSessionChannelInfo()
-{
- LLSD result;
-
- if (mAudioSession)
- {
- result = mAudioSession->getVoiceChannelInfo();
- }
-
- return result;
-}
-
-std::string LLVivoxVoiceClient::getAudioSessionHandle()
-{
- std::string result;
-
- if(mAudioSession)
- result = mAudioSession->mHandle;
-
- return result;
-}
-
-
-/////////////////////////////
-// Sending updates of current state
-
-void LLVivoxVoiceClient::enforceTether(void)
-{
- LLVector3d tethered = mCameraRequestedPosition;
-
- // constrain 'tethered' to within 50m of mAvatarPosition.
- {
- F32 max_dist = 50.0f;
- LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition;
- F32 camera_distance = (F32)camera_offset.magVec();
- if(camera_distance > max_dist)
- {
- tethered = mAvatarPosition +
- (max_dist / camera_distance) * camera_offset;
- }
- }
-
- if(dist_vec_squared(mCameraPosition, tethered) > 0.01)
- {
- mCameraPosition = tethered;
- mSpatialCoordsDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::updatePosition(void)
-{
-
- LLViewerRegion *region = gAgent.getRegion();
- if(region && isAgentAvatarValid())
- {
- LLMatrix3 rot;
- LLVector3d pos;
- LLQuaternion qrot;
-
- // TODO: If camera and avatar velocity are actually used by the voice system, we could compute them here...
- // They're currently always set to zero.
-
- // Send the current camera position to the voice code
- rot.setRows(LLViewerCamera::getInstance()->getAtAxis(), LLViewerCamera::getInstance()->getLeftAxis (), LLViewerCamera::getInstance()->getUpAxis());
- pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin());
-
- LLVivoxVoiceClient::getInstance()->setCameraPosition(
- pos, // position
- LLVector3::zero, // velocity
- rot); // rotation matrix
-
- // Send the current avatar position to the voice code
- qrot = gAgentAvatarp->getRootJoint()->getWorldRotation();
- pos = gAgentAvatarp->getPositionGlobal();
-
- // TODO: Can we get the head offset from outside the LLVOAvatar?
- // pos += LLVector3d(mHeadOffset);
- pos += LLVector3d(0.f, 0.f, 1.f);
-
- LLVivoxVoiceClient::getInstance()->setAvatarPosition(
- pos, // position
- LLVector3::zero, // velocity
- qrot); // rotation matrix
- }
-}
-
-void LLVivoxVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
-{
- mCameraRequestedPosition = position;
-
- if(mCameraVelocity != velocity)
- {
- mCameraVelocity = velocity;
- mSpatialCoordsDirty = true;
- }
-
- if(mCameraRot != rot)
- {
- mCameraRot = rot;
- mSpatialCoordsDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot)
-{
- if(dist_vec_squared(mAvatarPosition, position) > 0.01)
- {
- mAvatarPosition = position;
- mSpatialCoordsDirty = true;
- }
-
- if(mAvatarVelocity != velocity)
- {
- mAvatarVelocity = velocity;
- mSpatialCoordsDirty = true;
- }
-
- // If the two rotations are not exactly equal test their dot product
- // to get the cos of the angle between them.
- // If it is too small, don't update.
- F32 rot_cos_diff = llabs(dot(mAvatarRot, rot));
- if ((mAvatarRot != rot) && (rot_cos_diff < MINUSCULE_ANGLE_COS))
- {
- mAvatarRot = rot;
- mSpatialCoordsDirty = true;
- }
-}
-
-bool LLVivoxVoiceClient::channelFromRegion(LLViewerRegion *region, std::string &name)
-{
- bool result = false;
-
- if(region)
- {
- name = region->getName();
- }
-
- if(!name.empty())
- result = true;
-
- return result;
-}
-
-void LLVivoxVoiceClient::leaveChannel(void)
-{
- if (mIsInChannel)
- {
- LL_DEBUGS("Voice") << "leaving channel for teleport/logout" << LL_ENDL;
- mChannelName.clear();
- }
- sessionTerminate();
-}
-
-void LLVivoxVoiceClient::setMuteMic(bool muted)
-{
- if(mMuteMic != muted)
- {
- mMuteMic = muted;
- mMuteMicDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
-{
- LL_DEBUGS("Voice")
- << "( " << (enabled ? "enabled" : "disabled") << " )"
- << " was "<< (mVoiceEnabled ? "enabled" : "disabled")
- << " coro "<< (mIsCoroutineActive ? "active" : "inactive")
- << LL_ENDL;
-
- if (enabled != mVoiceEnabled)
- {
- // TODO: Refactor this so we don't call into LLVoiceChannel, but simply
- // use the status observer
- mVoiceEnabled = enabled;
- LLVoiceClientStatusObserver::EStatusType status;
-
- if (enabled)
- {
- LL_DEBUGS("Voice") << "enabling" << LL_ENDL;
- LLVoiceChannel::getCurrentVoiceChannel()->activate();
- status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED;
-
- if (!mIsCoroutineActive)
- {
- LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro",
- boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance()));
- }
- else
- {
- LL_DEBUGS("Voice") << "coro should be active.. not launching" << LL_ENDL;
- }
- }
- else
- {
- // Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it.
- LLVoiceChannel::getCurrentVoiceChannel()->deactivate();
- gAgent.setVoiceConnected(false);
- status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED;
- mCurrentParcelLocalID = -1;
- mCurrentRegionName.clear();
- }
-
- notifyStatusObservers(status);
- }
- else
- {
- LL_DEBUGS("Voice") << " no-op" << LL_ENDL;
- }
-}
-
-
-void LLVivoxVoiceClient::setEarLocation(S32 loc)
-{
- if(mEarLocation != loc)
- {
- LL_DEBUGS("Voice") << "Setting mEarLocation to " << loc << LL_ENDL;
-
- mEarLocation = loc;
- mSpatialCoordsDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::setVoiceVolume(F32 volume)
-{
- int scaled_volume = scale_speaker_volume(volume);
-
- if(scaled_volume != mSpeakerVolume)
- {
- int min_volume = scale_speaker_volume(0);
- if((scaled_volume == min_volume) || (mSpeakerVolume == min_volume))
- {
- mSpeakerMuteDirty = true;
- }
-
- mSpeakerVolume = scaled_volume;
- mSpeakerVolumeDirty = true;
- }
-}
-
-void LLVivoxVoiceClient::setMicGain(F32 volume)
-{
- int scaled_volume = scale_mic_volume(volume);
-
- if(scaled_volume != mMicVolume)
- {
- mMicVolume = scaled_volume;
- mMicVolumeDirty = true;
- }
-}
-
-/////////////////////////////
-// Accessors for data related to nearby speakers
-
-std::string LLVivoxVoiceClient::getDisplayName(const LLUUID& id)
-{
- std::string result;
- if (mProcessChannels)
- {
- participantStatePtr_t participant(findParticipantByID(id));
- if (participant)
- {
- result = participant->mDisplayName;
- }
- }
-
- return result;
-}
-
-
-
-bool LLVivoxVoiceClient::getIsSpeaking(const LLUUID& id)
-{
- bool result = false;
- if (mProcessChannels)
- {
- participantStatePtr_t participant(findParticipantByID(id));
- if (participant)
- {
- if (participant->mSpeakingTimeout.getElapsedTimeF32() > SPEAKING_TIMEOUT)
- {
- participant->mIsSpeaking = false;
- }
- result = participant->mIsSpeaking;
- }
- }
-
- return result;
-}
-
-bool LLVivoxVoiceClient::getIsModeratorMuted(const LLUUID& id)
-{
- bool result = false;
- if (!mProcessChannels)
- {
- return false;
- }
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->mIsModeratorMuted;
- }
-
- return result;
-}
-
-F32 LLVivoxVoiceClient::getCurrentPower(const LLUUID& id)
-{
- F32 result = 0;
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->mPower;
- }
-
- return result;
-}
-
-
-
-bool LLVivoxVoiceClient::getUsingPTT(const LLUUID& id)
-{
- bool result = false;
-
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- // I'm not sure what the semantics of this should be.
- // Does "using PTT" mean they're configured with a push-to-talk button?
- // For now, we know there's no PTT mechanism in place, so nobody is using it.
- }
-
- return result;
-}
-
-// External accessors.
-F32 LLVivoxVoiceClient::getUserVolume(const LLUUID& id)
-{
- // Minimum volume will be returned for users with voice disabled
- F32 result = LLVoiceClient::VOLUME_MIN;
-
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->mVolume;
-
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "mVolume = " << result << " for " << id << LL_ENDL;
- }
-
- return result;
-}
-
-void LLVivoxVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
-{
- if(mAudioSession)
- {
- participantStatePtr_t participant(findParticipantByID(id));
- if (participant && !participant->mIsSelf)
- {
- if (!is_approx_equal(volume, LLVoiceClient::VOLUME_DEFAULT))
- {
- // Store this volume setting for future sessions if it has been
- // changed from the default
- LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume);
- }
- else
- {
- // Remove stored volume setting if it is returned to the default
- LLSpeakerVolumeStorage::getInstance()->removeSpeakerVolume(id);
- }
-
- participant->mVolume = llclamp(volume, LLVoiceClient::VOLUME_MIN, LLVoiceClient::VOLUME_MAX);
- participant->mVolumeDirty = true;
- mAudioSession->mVolumeDirty = true;
- }
- }
-}
-
-std::string LLVivoxVoiceClient::getGroupID(const LLUUID& id)
-{
- std::string result;
-
- participantStatePtr_t participant(findParticipantByID(id));
- if(participant)
- {
- result = participant->mGroupID;
- }
-
- return result;
-}
-
-void LLVivoxVoiceClient::recordingLoopStart(int seconds, int deltaFramesPerControlFrame)
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Start)" << LL_ENDL;
-
- if(!mMainSessionGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Start</RecordingControlType>"
- << "<DeltaFramesPerControlFrame>" << deltaFramesPerControlFrame << "</DeltaFramesPerControlFrame>"
- << "<Filename>" << "" << "</Filename>"
- << "<EnableAudioRecordingEvents>false</EnableAudioRecordingEvents>"
- << "<LoopModeDurationSeconds>" << seconds << "</LoopModeDurationSeconds>"
- << "</Request>\n\n\n";
-
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::recordingLoopSave(const std::string& filename)
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Flush)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Flush</RecordingControlType>"
- << "<Filename>" << filename << "</Filename>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::recordingStop()
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Stop)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlRecording.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Stop</RecordingControlType>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::filePlaybackStart(const std::string& filename)
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Start)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Start</RecordingControlType>"
- << "<Filename>" << filename << "</Filename>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::filePlaybackStop()
-{
-// LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Stop)" << LL_ENDL;
-
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.ControlPlayback.1\">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Stop</RecordingControlType>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::filePlaybackSetPaused(bool paused)
-{
- // TODO: Implement once Vivox gives me a sample
-}
-
-void LLVivoxVoiceClient::filePlaybackSetMode(bool vox, float speed)
-{
- // TODO: Implement once Vivox gives me a sample
-}
-
-//------------------------------------------------------------------------
-std::set<LLVivoxVoiceClient::sessionState::wptr_t, std::owner_less<LLVivoxVoiceClient::sessionState::wptr_t>> LLVivoxVoiceClient::sessionState::mSession;
-
-
-LLVivoxVoiceClient::sessionState::sessionState() :
- mErrorStatusCode(0),
- mMediaStreamState(streamStateUnknown),
- mCreateInProgress(false),
- mMediaConnectInProgress(false),
- mVoiceInvitePending(false),
- mTextInvitePending(false),
- mSynthesizedCallerID(false),
- mIsChannel(false),
- mIsSpatial(false),
- mIsP2P(false),
- mIncoming(false),
- mVoiceActive(false),
- mReconnect(false),
- mVolumeDirty(false),
- mMuteDirty(false),
- mParticipantsChanged(false)
-{
-}
-
-LLSD LLVivoxVoiceClient::sessionState::getVoiceChannelInfo()
-{
- LLSD result;
-
- result["voice_server_type"] = VIVOX_VOICE_SERVER_TYPE;
- result["channel_credentials"] = mHash;
- result["channel_uri"] = mSIPURI;
- result["session_handle"] = mHandle;
-
- return result;
-}
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::createSession()
-{
- sessionState::ptr_t ptr(new sessionState());
-
- std::pair<std::set<wptr_t>::iterator, bool> result = mSession.insert(ptr);
-
- if (result.second)
- ptr->mMyIterator = result.first;
-
- return ptr;
-}
-
-LLVivoxVoiceClient::sessionState::~sessionState()
-{
- LL_INFOS("Voice") << "Destroying session handle=" << mHandle << " SIP=" << mSIPURI << LL_ENDL;
- if (mMyIterator != mSession.end())
- mSession.erase(mMyIterator);
-
- removeAllParticipants();
-}
-
-bool LLVivoxVoiceClient::sessionState::isCallBackPossible()
-{
- // This may change to be explicitly specified by vivox in the future...
- // Currently, only PSTN P2P calls cannot be returned.
- // Conveniently, this is also the only case where we synthesize a caller UUID.
- return !mSynthesizedCallerID;
-}
-
-bool LLVivoxVoiceClient::sessionState::isTextIMPossible()
-{
- // This may change to be explicitly specified by vivox in the future...
- return !mSynthesizedCallerID;
-}
-
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByHandle(const std::string &handle)
-{
- sessionStatePtr_t result;
-
- // *TODO: My kingdom for a lambda!
- std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByHandle, _1, handle));
-
- if (it != mSession.end())
- result = (*it).lock();
-
- return result;
-}
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchCreatingSessionByURI(const std::string &uri)
-{
- sessionStatePtr_t result;
-
- // *TODO: My kingdom for a lambda!
- std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByCreatingURI, _1, uri));
-
- if (it != mSession.end())
- result = (*it).lock();
-
- return result;
-}
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByURI(const std::string &uri)
-{
- sessionStatePtr_t result;
-
- // *TODO: My kingdom for a lambda!
- std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testBySIPOrAlterateURI, _1, uri));
-
- if (it != mSession.end())
- result = (*it).lock();
-
- return result;
-}
-
-/*static*/
-LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByParticipant(const LLUUID &participant_id)
-{
- sessionStatePtr_t result;
-
- // *TODO: My kingdom for a lambda!
- std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByCallerId, _1, participant_id));
-
- if (it != mSession.end())
- result = (*it).lock();
-
- return result;
-}
-
-void LLVivoxVoiceClient::sessionState::for_each(sessionFunc_t func)
-{
- std::for_each(mSession.begin(), mSession.end(), boost::bind(for_eachPredicate, _1, func));
-}
-
-// simple test predicates.
-// *TODO: These should be made into lambdas when we can pull the trigger on newer C++ features.
-bool LLVivoxVoiceClient::sessionState::testByHandle(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string handle)
-{
- ptr_t aLock(a.lock());
-
- return aLock ? aLock->mHandle == handle : false;
-}
-
-bool LLVivoxVoiceClient::sessionState::testByCreatingURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri)
-{
- ptr_t aLock(a.lock());
-
- return aLock ? (aLock->mCreateInProgress && (aLock->mSIPURI == uri)) : false;
-}
-
-bool LLVivoxVoiceClient::sessionState::testBySIPOrAlterateURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri)
-{
- ptr_t aLock(a.lock());
-
- return aLock ? ((aLock->mSIPURI == uri) || (aLock->mAlternateSIPURI == uri)) : false;
-}
-
-
-bool LLVivoxVoiceClient::sessionState::testByCallerId(const LLVivoxVoiceClient::sessionState::wptr_t &a, LLUUID participantId)
-{
- ptr_t aLock(a.lock());
-
- return aLock ? ((aLock->mCallerID == participantId) || (aLock->mIMSessionID == participantId)) : false;
-}
-
-/*static*/
-void LLVivoxVoiceClient::sessionState::for_eachPredicate(const LLVivoxVoiceClient::sessionState::wptr_t &a, sessionFunc_t func)
-{
- ptr_t aLock(a.lock());
-
- if (aLock)
- func(aLock);
- else
- {
- LL_WARNS("Voice") << "Stale handle in session map!" << LL_ENDL;
- }
-}
-
-
-
-LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSession(const std::string &handle)
-{
- sessionStatePtr_t result;
- sessionMap::iterator iter = mSessionsByHandle.find(handle);
- if(iter != mSessionsByHandle.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSessionBeingCreatedByURI(const std::string &uri)
-{
- sessionStatePtr_t result = sessionState::matchCreatingSessionByURI(uri);
-
- return result;
-}
-
-LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSession(const LLUUID &participant_id)
-{
- sessionStatePtr_t result = sessionState::matchSessionByParticipant(participant_id);
-
- return result;
-}
-
-LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::addSession(const std::string &uri, const std::string &handle)
-{
- sessionStatePtr_t result;
-
- if(handle.empty())
- {
- // No handle supplied.
- // Check whether there's already a session with this URI
- result = sessionState::matchSessionByURI(uri);
- }
- else // (!handle.empty())
- {
- // Check for an existing session with this handle
- sessionMap::iterator iter = mSessionsByHandle.find(handle);
-
- if(iter != mSessionsByHandle.end())
- {
- result = iter->second;
- }
- }
-
- if(!result)
- {
- // No existing session found.
-
- LL_DEBUGS("Voice") << "adding new session: handle \"" << handle << "\" URI " << uri << LL_ENDL;
- result = sessionState::createSession();
- result->mSIPURI = uri;
- result->mHandle = handle;
-
- if (LLVoiceClient::instance().getVoiceEffectEnabled())
- {
- result->mVoiceFontID = LLVoiceClient::instance().getVoiceEffectDefault();
- }
-
- if(!result->mHandle.empty())
- {
- // *TODO: Rider: This concerns me. There is a path (via switchChannel) where
- // we do not track the session. In theory this means that we could end up with
- // a mAuidoSession that does not match the session tracked in mSessionsByHandle
- mSessionsByHandle.insert(sessionMap::value_type(result->mHandle, result));
- }
- }
- else
- {
- // Found an existing session
-
- if(uri != result->mSIPURI)
- {
- // TODO: Should this be an internal error?
- LL_DEBUGS("Voice") << "changing uri from " << result->mSIPURI << " to " << uri << LL_ENDL;
- setSessionURI(result, uri);
- }
-
- if(handle != result->mHandle)
- {
- if(handle.empty())
- {
- // There's at least one race condition where where addSession was clearing an existing session handle, which caused things to break.
- LL_DEBUGS("Voice") << "NOT clearing handle " << result->mHandle << LL_ENDL;
- }
- else
- {
- // TODO: Should this be an internal error?
- LL_DEBUGS("Voice") << "changing handle from " << result->mHandle << " to " << handle << LL_ENDL;
- setSessionHandle(result, handle);
- }
- }
-
- LL_DEBUGS("Voice") << "returning existing session: handle " << handle << " URI " << uri << LL_ENDL;
- }
-
- verifySessionState();
-
- return result;
-}
-
-void LLVivoxVoiceClient::clearSessionHandle(const sessionStatePtr_t &session)
-{
- if (session)
- {
- if (!session->mHandle.empty())
- {
- sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle);
- if (iter != mSessionsByHandle.end())
- {
- mSessionsByHandle.erase(iter);
- }
- }
- else
- {
- LL_WARNS("Voice") << "Session has empty handle!" << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS("Voice") << "Attempt to clear NULL session!" << LL_ENDL;
- }
-
-}
-
-void LLVivoxVoiceClient::setSessionHandle(const sessionStatePtr_t &session, const std::string &handle)
-{
- // Have to remove the session from the handle-indexed map before changing the handle, or things will break badly.
-
- if(!session->mHandle.empty())
- {
- // Remove session from the map if it should have been there.
- sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle);
- if(iter != mSessionsByHandle.end())
- {
- if(iter->second != session)
- {
- LL_WARNS("Voice") << "Internal error: session mismatch! Session may have been duplicated. Removing version in map." << LL_ENDL;
- }
-
- mSessionsByHandle.erase(iter);
- }
- else
- {
- LL_WARNS("Voice") << "Attempt to remove session with handle " << session->mHandle << " not found in map!" << LL_ENDL;
- }
- }
-
- session->mHandle = handle;
-
- if(!handle.empty())
- {
- mSessionsByHandle.insert(sessionMap::value_type(session->mHandle, session));
- }
-
- verifySessionState();
-}
-
-void LLVivoxVoiceClient::setSessionURI(const sessionStatePtr_t &session, const std::string &uri)
-{
- // There used to be a map of session URIs to sessions, which made this complex....
- session->mSIPURI = uri;
-
- verifySessionState();
-}
-
-void LLVivoxVoiceClient::deleteSession(const sessionStatePtr_t &session)
-{
- // Remove the session from the handle map
- if(!session->mHandle.empty())
- {
- sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle);
- if(iter != mSessionsByHandle.end())
- {
- if(iter->second != session)
- {
- LL_WARNS("Voice") << "Internal error: session mismatch, removing session in map." << LL_ENDL;
- }
- mSessionsByHandle.erase(iter);
- }
- }
-
- // At this point, the session should be unhooked from all lists and all state should be consistent.
- verifySessionState();
-
- // If this is the current audio session, clean up the pointer which will soon be dangling.
- if(mAudioSession == session)
- {
- mAudioSession.reset();
- }
-
- // ditto for the next audio session
- if(mNextAudioSession == session)
- {
- mNextAudioSession.reset();
- }
-
-}
-
-void LLVivoxVoiceClient::deleteAllSessions()
-{
- LL_DEBUGS("Voice") << LL_ENDL;
-
- while (!mSessionsByHandle.empty())
- {
- const sessionStatePtr_t session = mSessionsByHandle.begin()->second;
- deleteSession(session);
- }
-
-}
-
-void LLVivoxVoiceClient::verifySessionState(void)
-{
- LL_DEBUGS("Voice") << "Sessions in handle map=" << mSessionsByHandle.size() << LL_ENDL;
- sessionState::VerifySessions();
-}
-
-void LLVivoxVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
-{
- mParticipantObservers.insert(observer);
-}
-
-void LLVivoxVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
-{
- mParticipantObservers.erase(observer);
-}
-
-void LLVivoxVoiceClient::notifyParticipantObservers()
-{
- for (observer_set_t::iterator it = mParticipantObservers.begin();
- it != mParticipantObservers.end();
- )
- {
- LLVoiceClientParticipantObserver* observer = *it;
- observer->onParticipantsChanged();
- // In case onParticipantsChanged() deleted an entry.
- it = mParticipantObservers.upper_bound(observer);
- }
-}
-
-void LLVivoxVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
-{
- mStatusObservers.insert(observer);
-}
-
-void LLVivoxVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
-{
- mStatusObservers.erase(observer);
-}
-
-void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status)
-{
- LL_DEBUGS("Voice") << "( " << LLVoiceClientStatusObserver::status2string(status) << " )"
- << " mAudioSession=" << mAudioSession
- << LL_ENDL;
-
- if(mAudioSession)
- {
- if(status == LLVoiceClientStatusObserver::ERROR_UNKNOWN)
- {
- switch(mAudioSession->mErrorStatusCode)
- {
- case 20713: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_FULL; break;
- case 20714: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_LOCKED; break;
- case 20715:
- //invalid channel, we may be using a set of poorly cached
- //info
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- break;
- case 1009:
- //invalid username and password
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- break;
- }
-
- // Reset the error code to make sure it won't be reused later by accident.
- mAudioSession->mErrorStatusCode = 0;
- }
- else if(status == LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL)
- {
- switch(mAudioSession->mErrorStatusCode)
- {
- case HTTP_NOT_FOUND: // NOT_FOUND
- // *TODO: Should this be 503?
- case 480: // TEMPORARILY_UNAVAILABLE
- case HTTP_REQUEST_TIME_OUT: // REQUEST_TIMEOUT
- // call failed because other user was not available
- // treat this as an error case
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
-
- // Reset the error code to make sure it won't be reused later by accident.
- mAudioSession->mErrorStatusCode = 0;
- break;
- }
- }
- }
-
- LLSD channel_info = getAudioSessionChannelInfo();
- LL_DEBUGS("Voice")
- << " " << LLVoiceClientStatusObserver::status2string(status)
- << ", session channelInfo " << channel_info
- << ", proximal is " << inSpatialChannel()
- << LL_ENDL;
-
- if (!mProcessChannels)
- {
- // we're not processing...another voice module is.
- // so nobody wants to hear from us.
- return;
- }
- for (status_observer_set_t::iterator it = mStatusObservers.begin();
- it != mStatusObservers.end();
- )
- {
- LLVoiceClientStatusObserver* observer = *it;
- observer->onChange(status, channel_info, inSpatialChannel());
- // In case onError() deleted an entry.
- it = mStatusObservers.upper_bound(observer);
- }
-
- // skipped to avoid speak button blinking
- if ( status != LLVoiceClientStatusObserver::STATUS_JOINING
- && status != LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL
- && status != LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED)
- {
- bool voice_status = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
-
- LL_WARNS("Voice") << "Setting voice connected " << (voice_status ? "True" : "False") << LL_ENDL;
- gAgent.setVoiceConnected(voice_status);
-
- if (voice_status)
- {
- LLAppViewer::instance()->postToMainCoro([=]() { LLFirstUse::speak(true); });
- }
- }
-}
-
-void LLVivoxVoiceClient::addObserver(LLFriendObserver* observer)
-{
- mFriendObservers.insert(observer);
-}
-
-void LLVivoxVoiceClient::removeObserver(LLFriendObserver* observer)
-{
- mFriendObservers.erase(observer);
-}
-
-void LLVivoxVoiceClient::notifyFriendObservers()
-{
- for (friend_observer_set_t::iterator it = mFriendObservers.begin();
- it != mFriendObservers.end();
- )
- {
- LLFriendObserver* observer = *it;
- it++;
- // The only friend-related thing we notify on is online/offline transitions.
- observer->changed(LLFriendObserver::ONLINE);
- }
-}
-
-void LLVivoxVoiceClient::lookupName(const LLUUID &id)
-{
- if (mAvatarNameCacheConnection.connected())
- {
- mAvatarNameCacheConnection.disconnect();
- }
- mAvatarNameCacheConnection = LLAvatarNameCache::get(id, boost::bind(&LLVivoxVoiceClient::onAvatarNameCache, this, _1, _2));
-}
-
-void LLVivoxVoiceClient::onAvatarNameCache(const LLUUID& agent_id,
- const LLAvatarName& av_name)
-{
- mAvatarNameCacheConnection.disconnect();
- std::string display_name = av_name.getDisplayName();
- avatarNameResolved(agent_id, display_name);
-}
-
-void LLVivoxVoiceClient::predAvatarNameResolution(const LLVivoxVoiceClient::sessionStatePtr_t &session, LLUUID id, std::string name)
-{
- participantStatePtr_t participant(session->findParticipantByID(id));
- if (participant)
- {
- // Found -- fill in the name
- participant->mAccountName = name;
- // and post a "participants updated" message to listeners later.
- session->mParticipantsChanged = true;
- }
-
- // Check whether this is a p2p session whose caller name just resolved
- if (session->mCallerID == id)
- {
- // this session's "caller ID" just resolved. Fill in the name.
- session->mName = name;
- if (session->mTextInvitePending)
- {
- session->mTextInvitePending = false;
-
- // We don't need to call LLIMMgr::getInstance()->addP2PSession() here. The first incoming message will create the panel.
- }
- if (session->mVoiceInvitePending)
- {
- session->mVoiceInvitePending = false;
- LLIMMgr::getInstance()->inviteToSession(
- session->mIMSessionID,
- session->mName,
- session->mCallerID,
- session->mName,
- IM_SESSION_P2P_INVITE,
- LLIMMgr::INVITATION_TYPE_VOICE,
- session->getVoiceChannelInfo());
- }
- }
-}
-
-void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name)
-{
- sessionState::for_each(boost::bind(predAvatarNameResolution, _1, id, name));
-}
-
-bool LLVivoxVoiceClient::setVoiceEffect(const LLUUID& id)
-{
- if (!mAudioSession)
- {
- return false;
- }
-
- if (!id.isNull())
- {
- if (mVoiceFontMap.empty())
- {
- LL_DEBUGS("Voice") << "Voice fonts not available." << LL_ENDL;
- return false;
- }
- else if (mVoiceFontMap.find(id) == mVoiceFontMap.end())
- {
- LL_DEBUGS("Voice") << "Invalid voice font " << id << LL_ENDL;
- return false;
- }
- }
-
- // *TODO: Check for expired fonts?
- mAudioSession->mVoiceFontID = id;
-
- // *TODO: Separate voice font defaults for spatial chat and IM?
- gSavedPerAccountSettings.setString("VoiceEffectDefault", id.asString());
-
- sessionSetVoiceFontSendMessage(mAudioSession);
- notifyVoiceFontObservers();
-
- return true;
-}
-
-const LLUUID LLVivoxVoiceClient::getVoiceEffect()
-{
- return mAudioSession ? mAudioSession->mVoiceFontID : LLUUID::null;
-}
-
-LLSD LLVivoxVoiceClient::getVoiceEffectProperties(const LLUUID& id)
-{
- LLSD sd;
-
- voice_font_map_t::iterator iter = mVoiceFontMap.find(id);
- if (iter != mVoiceFontMap.end())
- {
- sd["template_only"] = false;
- }
- else
- {
- // Voice effect is not in the voice font map, see if there is a template
- iter = mVoiceFontTemplateMap.find(id);
- if (iter == mVoiceFontTemplateMap.end())
- {
- LL_WARNS("Voice") << "Voice effect " << id << "not found." << LL_ENDL;
- return sd;
- }
- sd["template_only"] = true;
- }
-
- voiceFontEntry *font = iter->second;
- sd["name"] = font->mName;
- sd["expiry_date"] = font->mExpirationDate;
- sd["is_new"] = font->mIsNew;
-
- return sd;
-}
-
-LLVivoxVoiceClient::voiceFontEntry::voiceFontEntry(LLUUID& id) :
- mID(id),
- mFontIndex(0),
- mFontType(VOICE_FONT_TYPE_NONE),
- mFontStatus(VOICE_FONT_STATUS_NONE),
- mIsNew(false)
-{
- mExpiryTimer.stop();
-}
-
-LLVivoxVoiceClient::voiceFontEntry::~voiceFontEntry()
-{
-}
-
-void LLVivoxVoiceClient::refreshVoiceEffectLists(bool clear_lists)
-{
- if (clear_lists)
- {
- mVoiceFontsReceived = false;
- deleteAllVoiceFonts();
- deleteVoiceFontTemplates();
- }
-
- accountGetSessionFontsSendMessage();
- accountGetTemplateFontsSendMessage();
-}
-
-const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectList() const
-{
- return mVoiceFontList;
-}
-
-const voice_effect_list_t& LLVivoxVoiceClient::getVoiceEffectTemplateList() const
-{
- return mVoiceFontTemplateList;
-}
-
-void LLVivoxVoiceClient::addVoiceFont(const S32 font_index,
- const std::string &name,
- const std::string &description,
- const LLDate &expiration_date,
- bool has_expired,
- const S32 font_type,
- const S32 font_status,
- const bool template_font)
-{
- // Vivox SessionFontIDs are not guaranteed to remain the same between
- // sessions or grids so use a UUID for the name.
-
- // If received name is not a UUID, fudge one by hashing the name and type.
- LLUUID font_id;
- if (LLUUID::validate(name))
- {
- font_id = LLUUID(name);
- }
- else
- {
- font_id.generate(STRINGIZE(font_type << ":" << name));
- }
-
- voiceFontEntry *font = NULL;
-
- voice_font_map_t& font_map = template_font ? mVoiceFontTemplateMap : mVoiceFontMap;
- voice_effect_list_t& font_list = template_font ? mVoiceFontTemplateList : mVoiceFontList;
-
- // Check whether we've seen this font before.
- voice_font_map_t::iterator iter = font_map.find(font_id);
- bool new_font = (iter == font_map.end());
-
- // Override the has_expired flag if we have passed the expiration_date as a double check.
- if (expiration_date.secondsSinceEpoch() < (LLDate::now().secondsSinceEpoch() + VOICE_FONT_EXPIRY_INTERVAL))
- {
- has_expired = true;
- }
-
- if (has_expired)
- {
- LL_DEBUGS("VoiceFont") << "Expired " << (template_font ? "Template " : "")
- << expiration_date.asString() << " " << font_id
- << " (" << font_index << ") " << name << LL_ENDL;
-
- // Remove existing session fonts that have expired since we last saw them.
- if (!new_font && !template_font)
- {
- deleteVoiceFont(font_id);
- }
- return;
- }
-
- if (new_font)
- {
- // If it is a new font create a new entry.
- font = new voiceFontEntry(font_id);
- }
- else
- {
- // Not a new font, update the existing entry
- font = iter->second;
- }
-
- if (font)
- {
- font->mFontIndex = font_index;
- // Use the description for the human readable name if available, as the
- // "name" may be a UUID.
- font->mName = description.empty() ? name : description;
- font->mFontType = font_type;
- font->mFontStatus = font_status;
-
- // If the font is new or the expiration date has changed the expiry timers need updating.
- if (!template_font && (new_font || font->mExpirationDate != expiration_date))
- {
- font->mExpirationDate = expiration_date;
-
- // Set the expiry timer to trigger a notification when the voice font can no longer be used.
- font->mExpiryTimer.start();
- font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch() - VOICE_FONT_EXPIRY_INTERVAL);
-
- // Only flag new session fonts after the first time we have fetched the list.
- if (mVoiceFontsReceived)
- {
- font->mIsNew = true;
- mVoiceFontsNew = true;
- }
- }
-
- LL_DEBUGS("VoiceFont") << (template_font ? "Template " : "")
- << font->mExpirationDate.asString() << " " << font->mID
- << " (" << font->mFontIndex << ") " << name << LL_ENDL;
-
- if (new_font)
- {
- font_map.insert(voice_font_map_t::value_type(font->mID, font));
- font_list.insert(voice_effect_list_t::value_type(font->mName, font->mID));
- }
-
- mVoiceFontListDirty = true;
-
- // Debugging stuff
-
- if (font_type < VOICE_FONT_TYPE_NONE || font_type >= VOICE_FONT_TYPE_UNKNOWN)
- {
- LL_WARNS("VoiceFont") << "Unknown voice font type: " << font_type << LL_ENDL;
- }
- if (font_status < VOICE_FONT_STATUS_NONE || font_status >= VOICE_FONT_STATUS_UNKNOWN)
- {
- LL_WARNS("VoiceFont") << "Unknown voice font status: " << font_status << LL_ENDL;
- }
- }
-}
-
-void LLVivoxVoiceClient::expireVoiceFonts()
-{
- // *TODO: If we are selling voice fonts in packs, there are probably
- // going to be a number of fonts with the same expiration time, so would
- // be more efficient to just keep a list of expiration times rather
- // than checking each font individually.
-
- bool have_expired = false;
- bool expired_in_use = false;
-
- LLUUID current_effect = LLVoiceClient::instance().getVoiceEffectDefault();
-
- voice_font_map_t::iterator iter;
- for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter)
- {
- voiceFontEntry* voice_font = iter->second;
- LLFrameTimer& expiry_timer = voice_font->mExpiryTimer;
-
- // Check for expired voice fonts
- if (expiry_timer.getStarted() && expiry_timer.hasExpired())
- {
- // Check whether it is the active voice font
- if (voice_font->mID == current_effect)
- {
- // Reset to no voice effect.
- setVoiceEffect(LLUUID::null);
- expired_in_use = true;
- }
-
- LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " has expired." << LL_ENDL;
- deleteVoiceFont(voice_font->mID);
- have_expired = true;
- }
- }
-
- LLSD args;
- args["URL"] = LLTrans::getString("voice_morphing_url");
- args["PREMIUM_URL"] = LLTrans::getString("premium_voice_morphing_url");
-
- // Give a notification if any voice fonts have expired.
- if (have_expired)
- {
- if (expired_in_use)
- {
- LLNotificationsUtil::add("VoiceEffectsExpiredInUse", args);
- }
- else
- {
- LLNotificationsUtil::add("VoiceEffectsExpired", args);
- }
-
- // Refresh voice font lists in the UI.
- notifyVoiceFontObservers();
- }
-}
-
-void LLVivoxVoiceClient::deleteVoiceFont(const LLUUID& id)
-{
- // Remove the entry from the voice font list.
- voice_effect_list_t::iterator list_iter = mVoiceFontList.begin();
- while (list_iter != mVoiceFontList.end())
- {
- if (list_iter->second == id)
- {
- LL_DEBUGS("VoiceFont") << "Removing " << id << " from the voice font list." << LL_ENDL;
- list_iter = mVoiceFontList.erase(list_iter);
- mVoiceFontListDirty = true;
- }
- else
- {
- ++list_iter;
- }
- }
-
- // Find the entry in the voice font map and erase its data.
- voice_font_map_t::iterator map_iter = mVoiceFontMap.find(id);
- if (map_iter != mVoiceFontMap.end())
- {
- delete map_iter->second;
- }
-
- // Remove the entry from the voice font map.
- mVoiceFontMap.erase(map_iter);
-}
-
-void LLVivoxVoiceClient::deleteAllVoiceFonts()
-{
- mVoiceFontList.clear();
-
- voice_font_map_t::iterator iter;
- for (iter = mVoiceFontMap.begin(); iter != mVoiceFontMap.end(); ++iter)
- {
- delete iter->second;
- }
- mVoiceFontMap.clear();
-}
-
-void LLVivoxVoiceClient::deleteVoiceFontTemplates()
-{
- mVoiceFontTemplateList.clear();
-
- voice_font_map_t::iterator iter;
- for (iter = mVoiceFontTemplateMap.begin(); iter != mVoiceFontTemplateMap.end(); ++iter)
- {
- delete iter->second;
- }
- mVoiceFontTemplateMap.clear();
-}
-
-S32 LLVivoxVoiceClient::getVoiceFontIndex(const LLUUID& id) const
-{
- S32 result = 0;
- if (!id.isNull())
- {
- voice_font_map_t::const_iterator it = mVoiceFontMap.find(id);
- if (it != mVoiceFontMap.end())
- {
- result = it->second->mFontIndex;
- }
- else
- {
- LL_WARNS("VoiceFont") << "Selected voice font " << id << " is not available." << LL_ENDL;
- }
- }
- return result;
-}
-
-S32 LLVivoxVoiceClient::getVoiceFontTemplateIndex(const LLUUID& id) const
-{
- S32 result = 0;
- if (!id.isNull())
- {
- voice_font_map_t::const_iterator it = mVoiceFontTemplateMap.find(id);
- if (it != mVoiceFontTemplateMap.end())
- {
- result = it->second->mFontIndex;
- }
- else
- {
- LL_WARNS("VoiceFont") << "Selected voice font template " << id << " is not available." << LL_ENDL;
- }
- }
- return result;
-}
-
-void LLVivoxVoiceClient::accountGetSessionFontsSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("VoiceFont") << "Requesting voice font list." << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.GetSessionFonts.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::accountGetTemplateFontsSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("VoiceFont") << "Requesting voice font template list." << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.GetTemplateFonts.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::sessionSetVoiceFontSendMessage(const sessionStatePtr_t &session)
-{
- S32 font_index = getVoiceFontIndex(session->mVoiceFontID);
- LL_DEBUGS("VoiceFont") << "Requesting voice font: " << session->mVoiceFontID << " (" << font_index << "), session handle: " << session->mHandle << LL_ENDL;
-
- std::ostringstream stream;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetVoiceFont.1\">"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<SessionFontID>" << font_index << "</SessionFontID>"
- << "</Request>\n\n\n";
-
- writeString(stream.str());
-}
-
-void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const std::string &statusString)
-{
- if (mIsWaitingForFonts)
- {
- // *TODO: We seem to get multiple events of this type. Should figure a way to advance only after
- // receiving the last one.
- LLSD result(LLSDMap("voice_fonts", LLSD::Boolean(true)));
-
- mVivoxPump.post(result);
- }
- notifyVoiceFontObservers();
- mVoiceFontsReceived = true;
-}
-
-void LLVivoxVoiceClient::accountGetTemplateFontsResponse(int statusCode, const std::string &statusString)
-{
- // Voice font list entries were updated via addVoiceFont() during parsing.
- notifyVoiceFontObservers();
-}
-void LLVivoxVoiceClient::addObserver(LLVoiceEffectObserver* observer)
-{
- mVoiceFontObservers.insert(observer);
-}
-
-void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer)
-{
- mVoiceFontObservers.erase(observer);
-}
-
-// method checks the item in VoiceMorphing menu for appropriate current voice font
-bool LLVivoxVoiceClient::onCheckVoiceEffect(const std::string& voice_effect_name)
-{
- LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
- if (NULL != effect_interfacep)
- {
- const LLUUID& currect_voice_effect_id = effect_interfacep->getVoiceEffect();
-
- if (currect_voice_effect_id.isNull())
- {
- if (voice_effect_name == "NoVoiceMorphing")
- {
- return true;
- }
- }
- else
- {
- const LLSD& voice_effect_props = effect_interfacep->getVoiceEffectProperties(currect_voice_effect_id);
- if (voice_effect_props["name"].asString() == voice_effect_name)
- {
- return true;
- }
- }
- }
-
- return false;
-}
-
-// method changes voice font for selected VoiceMorphing menu item
-void LLVivoxVoiceClient::onClickVoiceEffect(const std::string& voice_effect_name)
-{
- LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
- if (NULL != effect_interfacep)
- {
- if (voice_effect_name == "NoVoiceMorphing")
- {
- effect_interfacep->setVoiceEffect(LLUUID());
- return;
- }
- const voice_effect_list_t& effect_list = effect_interfacep->getVoiceEffectList();
- if (!effect_list.empty())
- {
- for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
- {
- if (voice_effect_name == it->first)
- {
- effect_interfacep->setVoiceEffect(it->second);
- return;
- }
- }
- }
- }
-}
-
-// it updates VoiceMorphing menu items in accordance with purchased properties
-void LLVivoxVoiceClient::updateVoiceMorphingMenu()
-{
- if (mVoiceFontListDirty)
- {
- LLVoiceEffectInterface * effect_interfacep = LLVoiceClient::instance().getVoiceEffectInterface();
- if (effect_interfacep)
- {
- const voice_effect_list_t& effect_list = effect_interfacep->getVoiceEffectList();
- if (!effect_list.empty())
- {
- LLMenuGL * voice_morphing_menup = gMenuBarView->findChildMenuByName("VoiceMorphing", true);
-
- if (NULL != voice_morphing_menup)
- {
- S32 items = voice_morphing_menup->getItemCount();
- if (items > 0)
- {
- voice_morphing_menup->erase(1, items - 3, false);
-
- S32 pos = 1;
- for (voice_effect_list_t::const_iterator it = effect_list.begin(); it != effect_list.end(); ++it)
- {
- LLMenuItemCheckGL::Params p;
- p.name = it->first;
- p.label = it->first;
- p.on_check.function(boost::bind(&LLVivoxVoiceClient::onCheckVoiceEffect, this, it->first));
- p.on_click.function(boost::bind(&LLVivoxVoiceClient::onClickVoiceEffect, this, it->first));
- LLMenuItemCheckGL * voice_effect_itemp = LLUICtrlFactory::create<LLMenuItemCheckGL>(p);
- voice_morphing_menup->insert(pos++, voice_effect_itemp, false);
- }
-
- voice_morphing_menup->needsArrange();
- }
- }
- }
- }
- }
-}
-void LLVivoxVoiceClient::notifyVoiceFontObservers()
-{
- LL_DEBUGS("VoiceFont") << "Notifying voice effect observers. Lists changed: " << mVoiceFontListDirty << LL_ENDL;
-
- updateVoiceMorphingMenu();
-
- for (voice_font_observer_set_t::iterator it = mVoiceFontObservers.begin();
- it != mVoiceFontObservers.end();)
- {
- LLVoiceEffectObserver* observer = *it;
- observer->onVoiceEffectChanged(mVoiceFontListDirty);
- // In case onVoiceEffectChanged() deleted an entry.
- it = mVoiceFontObservers.upper_bound(observer);
- }
- mVoiceFontListDirty = false;
-
- // If new Voice Fonts have been added notify the user.
- if (mVoiceFontsNew)
- {
- if (mVoiceFontsReceived)
- {
- LLNotificationsUtil::add("VoiceEffectsNew");
- }
- mVoiceFontsNew = false;
- }
-}
-
-void LLVivoxVoiceClient::enablePreviewBuffer(bool enable)
-{
- LLSD result;
- mCaptureBufferMode = enable;
-
- if (enable)
- result["recplay"] = "start";
- else
- result["recplay"] = "quit";
-
- mVivoxPump.post(result);
-
- if(mCaptureBufferMode && mIsInChannel)
- {
- LL_DEBUGS("Voice") << "no channel" << LL_ENDL;
- sessionTerminate();
- }
-}
-
-void LLVivoxVoiceClient::recordPreviewBuffer()
-{
- if (!mCaptureBufferMode)
- {
- LL_DEBUGS("Voice") << "Not in voice effect preview mode, cannot start recording." << LL_ENDL;
- mCaptureBufferRecording = false;
- return;
- }
-
- mCaptureBufferRecording = true;
-
- LLSD result(LLSDMap("recplay", "record"));
- mVivoxPump.post(result);
-}
-
-void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id)
-{
- if (!mCaptureBufferMode)
- {
- LL_DEBUGS("Voice") << "Not in voice effect preview mode, no buffer to play." << LL_ENDL;
- mCaptureBufferRecording = false;
- return;
- }
-
- if (!mCaptureBufferRecorded)
- {
- // Can't play until we have something recorded!
- mCaptureBufferPlaying = false;
- return;
- }
-
- mPreviewVoiceFont = effect_id;
- mCaptureBufferPlaying = true;
-
- LLSD result(LLSDMap("recplay", "playback"));
- mVivoxPump.post(result);
-}
-
-void LLVivoxVoiceClient::stopPreviewBuffer()
-{
- mCaptureBufferRecording = false;
- mCaptureBufferPlaying = false;
-
- LLSD result(LLSDMap("recplay", "quit"));
- mVivoxPump.post(result);
-}
-
-bool LLVivoxVoiceClient::isPreviewRecording()
-{
- return (mCaptureBufferMode && mCaptureBufferRecording);
-}
-
-bool LLVivoxVoiceClient::isPreviewPlaying()
-{
- return (mCaptureBufferMode && mCaptureBufferPlaying);
-}
-
-void LLVivoxVoiceClient::captureBufferRecordStartSendMessage()
-{ if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Starting audio capture to buffer." << LL_ENDL;
-
- // Start capture
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.StartBufferCapture.1\">"
- << "</Request>"
- << "\n\n\n";
-
- // Unmute the mic
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>false</Value>"
- << "</Request>\n\n\n";
-
- // Dirty the mute mic state so that it will get reset when we finishing previewing
- mMuteMicDirty = true;
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::captureBufferRecordStopSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Stopping audio capture to buffer." << LL_ENDL;
-
- // Mute the mic. Mic mute state was dirtied at recording start, so will be reset when finished previewing.
- stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
- << "<ConnectorHandle>" << LLVivoxSecurity::getInstance()->connectorHandle() << "</ConnectorHandle>"
- << "<Value>true</Value>"
- << "</Request>\n\n\n";
-
- // Stop capture
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::captureBufferPlayStartSendMessage(const LLUUID& voice_font_id)
-{
- if(mAccountLoggedIn)
- {
- // Track how may play requests are sent, so we know how many stop events to
- // expect before play actually stops.
- ++mPlayRequestCount;
-
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Starting audio buffer playback." << LL_ENDL;
-
- S32 font_index = getVoiceFontTemplateIndex(voice_font_id);
- LL_DEBUGS("Voice") << "With voice font: " << voice_font_id << " (" << font_index << ")" << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.PlayAudioBuffer.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "<TemplateFontID>" << font_index << "</TemplateFontID>"
- << "<FontDelta />"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-void LLVivoxVoiceClient::captureBufferPlayStopSendMessage()
-{
- if(mAccountLoggedIn)
- {
- std::ostringstream stream;
-
- LL_DEBUGS("Voice") << "Stopping audio buffer playback." << LL_ENDL;
-
- stream
- << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
- << "<AccountHandle>" << LLVivoxSecurity::getInstance()->accountHandle() << "</AccountHandle>"
- << "</Request>"
- << "\n\n\n";
-
- writeString(stream.str());
- }
-}
-
-LLVivoxProtocolParser::LLVivoxProtocolParser()
-{
- parser = XML_ParserCreate(NULL);
-
- reset();
-}
-
-void LLVivoxProtocolParser::reset()
-{
- responseDepth = 0;
- ignoringTags = false;
- accumulateText = false;
- energy = 0.f;
- hasText = false;
- hasAudio = false;
- hasVideo = false;
- terminated = false;
- ignoreDepth = 0;
- isChannel = false;
- incoming = false;
- enabled = false;
- isEvent = false;
- isLocallyMuted = false;
- isModeratorMuted = false;
- isSpeaking = false;
- participantType = 0;
- returnCode = -1;
- state = 0;
- statusCode = 0;
- volume = 0;
- textBuffer.clear();
- alias.clear();
- numberOfAliases = 0;
- applicationString.clear();
-}
-
-//virtual
-LLVivoxProtocolParser::~LLVivoxProtocolParser()
-{
- if (parser)
- XML_ParserFree(parser);
-}
-
-static LLTrace::BlockTimerStatHandle FTM_VIVOX_PROCESS("Vivox Process");
-
-// virtual
-LLIOPipe::EStatus LLVivoxProtocolParser::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_VIVOX_PROCESS);
- LLBufferStream istr(channels, buffer.get());
- std::ostringstream ostr;
- while (istr.good())
- {
- char buf[1024];
- istr.read(buf, sizeof(buf));
- mInput.append(buf, istr.gcount());
- }
-
- // Look for input delimiter(s) in the input buffer. If one is found, send the message to the xml parser.
- size_t start = 0;
- size_t delim;
- while((delim = mInput.find("\n\n\n", start)) != std::string::npos)
- {
-
- // Reset internal state of the LLVivoxProtocolParser (no effect on the expat parser)
- reset();
-
- XML_ParserReset(parser, NULL);
- XML_SetElementHandler(parser, ExpatStartTag, ExpatEndTag);
- XML_SetCharacterDataHandler(parser, ExpatCharHandler);
- XML_SetUserData(parser, this);
- XML_Parse(parser, mInput.data() + start, static_cast<int>(delim - start), false);
-
-
- LL_DEBUGS("VivoxProtocolParser") << "parsing: " << mInput.substr(start, delim - start) << LL_ENDL;
- start = delim + 3;
- }
-
- if(start != 0)
- mInput = mInput.substr(start);
-
- LL_DEBUGS("VivoxProtocolParser") << "at end, mInput is: " << mInput << LL_ENDL;
-
- if(!LLVivoxVoiceClient::sConnected)
- {
- // If voice has been disabled, we just want to close the socket. This does so.
- LL_INFOS("Voice") << "returning STATUS_STOP" << LL_ENDL;
- return STATUS_STOP;
- }
-
- return STATUS_OK;
-}
-
-void XMLCALL LLVivoxProtocolParser::ExpatStartTag(void *data, const char *el, const char **attr)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->StartTag(el, attr);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void XMLCALL LLVivoxProtocolParser::ExpatEndTag(void *data, const char *el)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->EndTag(el);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void XMLCALL LLVivoxProtocolParser::ExpatCharHandler(void *data, const XML_Char *s, int len)
-{
- if (data)
- {
- LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
- object->CharData(s, len);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-
-void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
-{
- // Reset the text accumulator. We shouldn't have strings that are inturrupted by new tags
- textBuffer.clear();
- // only accumulate text if we're not ignoring tags.
- accumulateText = !ignoringTags;
-
- if (responseDepth == 0)
- {
- isEvent = !stricmp("Event", tag);
-
- if (!stricmp("Response", tag) || isEvent)
- {
- // Grab the attributes
- while (*attr)
- {
- const char *key = *attr++;
- const char *value = *attr++;
-
- if (!stricmp("requestId", key))
- {
- requestId = value;
- }
- else if (!stricmp("action", key))
- {
- actionString = value;
- }
- else if (!stricmp("type", key))
- {
- eventTypeString = value;
- }
- }
- }
- LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")" << LL_ENDL;
- }
- else
- {
- if (ignoringTags)
- {
- LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("VivoxProtocolParser") << tag << " (" << responseDepth << ")" << LL_ENDL;
-
- // Ignore the InputXml stuff so we don't get confused
- if (!stricmp("InputXml", tag))
- {
- ignoringTags = true;
- ignoreDepth = responseDepth;
- accumulateText = false;
-
- LL_DEBUGS("VivoxProtocolParser") << "starting ignore, ignoreDepth is " << ignoreDepth << LL_ENDL;
- }
- else if (!stricmp("CaptureDevices", tag))
- {
- LLVivoxVoiceClient::getInstance()->clearCaptureDevices();
- }
- else if (!stricmp("RenderDevices", tag))
- {
- LLVivoxVoiceClient::getInstance()->clearRenderDevices();
- }
- else if (!stricmp("CaptureDevice", tag))
- {
- deviceString.clear();
- }
- else if (!stricmp("RenderDevice", tag))
- {
- deviceString.clear();
- }
- else if (!stricmp("SessionFont", tag))
- {
- id = 0;
- nameString.clear();
- descriptionString.clear();
- expirationDate = LLDate();
- hasExpired = false;
- fontType = 0;
- fontStatus = 0;
- }
- else if (!stricmp("TemplateFont", tag))
- {
- id = 0;
- nameString.clear();
- descriptionString.clear();
- expirationDate = LLDate();
- hasExpired = false;
- fontType = 0;
- fontStatus = 0;
- }
- else if (!stricmp("MediaCompletionType", tag))
- {
- mediaCompletionType.clear();
- }
- }
- }
- responseDepth++;
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::EndTag(const char *tag)
-{
- const std::string& string = textBuffer;
-
- responseDepth--;
-
- if (ignoringTags)
- {
- if (ignoreDepth == responseDepth)
- {
- LL_DEBUGS("VivoxProtocolParser") << "end of ignore" << LL_ENDL;
- ignoringTags = false;
- }
- else
- {
- LL_DEBUGS("VivoxProtocolParser") << "ignoring tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
- }
- }
-
- if (!ignoringTags)
- {
- LL_DEBUGS("VivoxProtocolParser") << "processing tag " << tag << " (depth = " << responseDepth << ")" << LL_ENDL;
-
- // Closing a tag. Finalize the text we've accumulated and reset
- if (!stricmp("ReturnCode", tag))
- returnCode = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("SessionHandle", tag))
- sessionHandle = string;
- else if (!stricmp("SessionGroupHandle", tag))
- sessionGroupHandle = string;
- else if (!stricmp("StatusCode", tag))
- statusCode = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("StatusString", tag))
- statusString = string;
- else if (!stricmp("ParticipantURI", tag))
- uriString = string;
- else if (!stricmp("Volume", tag))
- volume = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("Energy", tag))
- energy = (F32)strtod(string.c_str(), NULL);
- else if (!stricmp("IsModeratorMuted", tag))
- isModeratorMuted = !stricmp(string.c_str(), "true");
- else if (!stricmp("IsSpeaking", tag))
- isSpeaking = !stricmp(string.c_str(), "true");
- else if (!stricmp("Alias", tag))
- alias = string;
- else if (!stricmp("NumberOfAliases", tag))
- numberOfAliases = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("Application", tag))
- applicationString = string;
- else if (!stricmp("ConnectorHandle", tag))
- connectorHandle = string;
- else if (!stricmp("VersionID", tag))
- versionID = string;
- else if (!stricmp("Version", tag))
- mBuildID = string;
- else if (!stricmp("AccountHandle", tag))
- accountHandle = string;
- else if (!stricmp("State", tag))
- state = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("URI", tag))
- uriString = string;
- else if (!stricmp("IsChannel", tag))
- isChannel = !stricmp(string.c_str(), "true");
- else if (!stricmp("Incoming", tag))
- incoming = !stricmp(string.c_str(), "true");
- else if (!stricmp("Enabled", tag))
- enabled = !stricmp(string.c_str(), "true");
- else if (!stricmp("Name", tag))
- nameString = string;
- else if (!stricmp("AudioMedia", tag))
- audioMediaString = string;
- else if (!stricmp("ChannelName", tag))
- nameString = string;
- else if (!stricmp("DisplayName", tag))
- displayNameString = string;
- else if (!stricmp("Device", tag))
- deviceString = string;
- else if (!stricmp("AccountName", tag))
- nameString = string;
- else if (!stricmp("ParticipantType", tag))
- participantType = strtol(string.c_str(), NULL, 10);
- else if (!stricmp("IsLocallyMuted", tag))
- isLocallyMuted = !stricmp(string.c_str(), "true");
- else if (!stricmp("MicEnergy", tag))
- energy = (F32)strtod(string.c_str(), NULL);
- else if (!stricmp("ChannelName", tag))
- nameString = string;
- else if (!stricmp("ChannelURI", tag))
- uriString = string;
- else if (!stricmp("BuddyURI", tag))
- uriString = string;
- else if (!stricmp("Presence", tag))
- statusString = string;
- else if (!stricmp("CaptureDevices", tag))
- {
- LLVivoxVoiceClient::getInstance()->setDevicesListUpdated(true);
- }
- else if (!stricmp("RenderDevices", tag))
- {
- LLVivoxVoiceClient::getInstance()->setDevicesListUpdated(true);
- }
- else if (!stricmp("CaptureDevice", tag))
- {
- LLVivoxVoiceClient::getInstance()->addCaptureDevice(LLVoiceDevice(displayNameString, deviceString));
- }
- else if (!stricmp("RenderDevice", tag))
- {
- LLVivoxVoiceClient::getInstance()->addRenderDevice(LLVoiceDevice(displayNameString, deviceString));
- }
- else if (!stricmp("BlockMask", tag))
- blockMask = string;
- else if (!stricmp("PresenceOnly", tag))
- presenceOnly = string;
- else if (!stricmp("AutoAcceptMask", tag))
- autoAcceptMask = string;
- else if (!stricmp("AutoAddAsBuddy", tag))
- autoAddAsBuddy = string;
- else if (!stricmp("MessageHeader", tag))
- messageHeader = string;
- else if (!stricmp("MessageBody", tag))
- messageBody = string;
- else if (!stricmp("NotificationType", tag))
- notificationType = string;
- else if (!stricmp("HasText", tag))
- hasText = !stricmp(string.c_str(), "true");
- else if (!stricmp("HasAudio", tag))
- hasAudio = !stricmp(string.c_str(), "true");
- else if (!stricmp("HasVideo", tag))
- hasVideo = !stricmp(string.c_str(), "true");
- else if (!stricmp("Terminated", tag))
- terminated = !stricmp(string.c_str(), "true");
- else if (!stricmp("SubscriptionHandle", tag))
- subscriptionHandle = string;
- else if (!stricmp("SubscriptionType", tag))
- subscriptionType = string;
- else if (!stricmp("SessionFont", tag))
- {
- LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, hasExpired, fontType, fontStatus, false);
- }
- else if (!stricmp("TemplateFont", tag))
- {
- LLVivoxVoiceClient::getInstance()->addVoiceFont(id, nameString, descriptionString, expirationDate, hasExpired, fontType, fontStatus, true);
- }
- else if (!stricmp("ID", tag))
- {
- id = strtol(string.c_str(), NULL, 10);
- }
- else if (!stricmp("Description", tag))
- {
- descriptionString = string;
- }
- else if (!stricmp("ExpirationDate", tag))
- {
- expirationDate = expiryTimeStampToLLDate(string);
- }
- else if (!stricmp("Expired", tag))
- {
- hasExpired = !stricmp(string.c_str(), "1");
- }
- else if (!stricmp("Type", tag))
- {
- fontType = strtol(string.c_str(), NULL, 10);
- }
- else if (!stricmp("Status", tag))
- {
- fontStatus = strtol(string.c_str(), NULL, 10);
- }
- else if (!stricmp("MediaCompletionType", tag))
- {
- mediaCompletionType = string;;
- }
-
- textBuffer.clear();
- accumulateText= false;
-
- if (responseDepth == 0)
- {
- // We finished all of the XML, process the data
- processResponse(tag);
- }
- }
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::CharData(const char *buffer, int length)
-{
- /*
- This method is called for anything that isn't a tag, which can be text you
- want that lies between tags, and a lot of stuff you don't want like file formatting
- (tabs, spaces, CR/LF, etc).
-
- Only copy text if we are in accumulate mode...
- */
- if (accumulateText)
- textBuffer.append(buffer, length);
-}
-
-// --------------------------------------------------------------------------------
-
-LLDate LLVivoxProtocolParser::expiryTimeStampToLLDate(const std::string& vivox_ts)
-{
- // *HACK: Vivox reports the time incorrectly. LLDate also only parses a
- // subset of valid ISO 8601 dates (only handles Z, not offsets).
- // So just use the date portion and fix the time here.
- std::string time_stamp = vivox_ts.substr(0, 10);
- time_stamp += VOICE_FONT_EXPIRY_TIME;
-
- LL_DEBUGS("VivoxProtocolParser") << "Vivox timestamp " << vivox_ts << " modified to: " << time_stamp << LL_ENDL;
-
- return LLDate(time_stamp);
-}
-
-// --------------------------------------------------------------------------------
-
-void LLVivoxProtocolParser::processResponse(std::string tag)
-{
- LL_DEBUGS("VivoxProtocolParser") << tag << LL_ENDL;
-
- // SLIM SDK: the SDK now returns a statusCode of "200" (OK) for success. This is a change vs. previous SDKs.
- // According to Mike S., "The actual API convention is that responses with return codes of 0 are successful, regardless of the status code returned",
- // so I believe this will give correct behavior.
-
- if(returnCode == 0)
- statusCode = 0;
-
- if (isEvent)
- {
- const char *eventTypeCstr = eventTypeString.c_str();
- LL_DEBUGS("LowVoice") << eventTypeCstr << LL_ENDL;
-
- if (!stricmp(eventTypeCstr, "ParticipantUpdatedEvent"))
- {
- // These happen so often that logging them is pretty useless.
- LL_DEBUGS("LowVoice") << "Updated Params: " << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << isModeratorMuted << ", " << isSpeaking << ", " << volume << ", " << energy << LL_ENDL;
- LLVivoxVoiceClient::getInstance()->participantUpdatedEvent(sessionHandle, sessionGroupHandle, uriString, alias, isModeratorMuted, isSpeaking, volume, energy);
- }
- else if (!stricmp(eventTypeCstr, "AccountLoginStateChangeEvent"))
- {
- LLVivoxVoiceClient::getInstance()->accountLoginStateChangeEvent(accountHandle, statusCode, statusString, state);
- }
- else if (!stricmp(eventTypeCstr, "SessionAddedEvent"))
- {
- /*
- <Event type="SessionAddedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <Uri>sip:confctl-1408789@bhr.vivox.com</Uri>
- <IsChannel>true</IsChannel>
- <Incoming>false</Incoming>
- <ChannelName />
- </Event>
- */
- LLVivoxVoiceClient::getInstance()->sessionAddedEvent(uriString, alias, sessionHandle, sessionGroupHandle, isChannel, incoming, nameString, applicationString);
- }
- else if (!stricmp(eventTypeCstr, "SessionRemovedEvent"))
- {
- LLVivoxVoiceClient::getInstance()->sessionRemovedEvent(sessionHandle, sessionGroupHandle);
- }
- else if (!stricmp(eventTypeCstr, "SessionGroupUpdatedEvent"))
- {
- //nothng useful to process for this event, but we should not WARN that we have received it.
- }
- else if (!stricmp(eventTypeCstr, "SessionGroupAddedEvent"))
- {
- LLVivoxVoiceClient::getInstance()->sessionGroupAddedEvent(sessionGroupHandle);
- }
- else if (!stricmp(eventTypeCstr, "MediaStreamUpdatedEvent"))
- {
- /*
- <Event type="MediaStreamUpdatedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <StatusCode>200</StatusCode>
- <StatusString>OK</StatusString>
- <State>2</State>
- <Incoming>false</Incoming>
- </Event>
- */
- LLVivoxVoiceClient::getInstance()->mediaStreamUpdatedEvent(sessionHandle, sessionGroupHandle, statusCode, statusString, state, incoming);
- }
- else if (!stricmp(eventTypeCstr, "MediaCompletionEvent"))
- {
- /*
- <Event type="MediaCompletionEvent">
- <SessionGroupHandle />
- <MediaCompletionType>AuxBufferAudioCapture</MediaCompletionType>
- </Event>
- */
- LLVivoxVoiceClient::getInstance()->mediaCompletionEvent(sessionGroupHandle, mediaCompletionType);
- }
- else if (!stricmp(eventTypeCstr, "ParticipantAddedEvent"))
- {
- /*
- <Event type="ParticipantAddedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle>
- <ParticipantUri>sip:xI5auBZ60SJWIk606-1JGRQ==@bhr.vivox.com</ParticipantUri>
- <AccountName>xI5auBZ60SJWIk606-1JGRQ==</AccountName>
- <DisplayName />
- <ParticipantType>0</ParticipantType>
- </Event>
- */
- LL_DEBUGS("LowVoice") << "Added Params: " << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << nameString << ", " << displayNameString << ", " << participantType << LL_ENDL;
- LLVivoxVoiceClient::getInstance()->participantAddedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString, displayNameString, participantType);
- }
- else if (!stricmp(eventTypeCstr, "ParticipantRemovedEvent"))
- {
- /*
- <Event type="ParticipantRemovedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg4</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==4</SessionHandle>
- <ParticipantUri>sip:xtx7YNV-3SGiG7rA1fo5Ndw==@bhr.vivox.com</ParticipantUri>
- <AccountName>xtx7YNV-3SGiG7rA1fo5Ndw==</AccountName>
- </Event>
- */
- LL_DEBUGS("LowVoice") << "Removed params:" << sessionHandle << ", " << sessionGroupHandle << ", " << uriString << ", " << alias << ", " << nameString << LL_ENDL;
-
- LLVivoxVoiceClient::getInstance()->participantRemovedEvent(sessionHandle, sessionGroupHandle, uriString, alias, nameString);
- }
- else if (!stricmp(eventTypeCstr, "AuxAudioPropertiesEvent"))
- {
- // These are really spammy in tuning mode
- LLVivoxVoiceClient::getInstance()->auxAudioPropertiesEvent(energy);
- }
- else if (!stricmp(eventTypeCstr, "MessageEvent"))
- {
- //TODO: This probably is not received any more, it was used to support SLim clients
- LLVivoxVoiceClient::getInstance()->messageEvent(sessionHandle, uriString, alias, messageHeader, messageBody, applicationString);
- }
- else if (!stricmp(eventTypeCstr, "SessionNotificationEvent"))
- {
- //TODO: This probably is not received any more, it was used to support SLim clients
- LLVivoxVoiceClient::getInstance()->sessionNotificationEvent(sessionHandle, uriString, notificationType);
- }
- else if (!stricmp(eventTypeCstr, "SessionUpdatedEvent"))
- {
- /*
- <Event type="SessionUpdatedEvent">
- <SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
- <SessionHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==0</SessionHandle>
- <Uri>sip:confctl-9@bhd.vivox.com</Uri>
- <IsMuted>0</IsMuted>
- <Volume>50</Volume>
- <TransmitEnabled>1</TransmitEnabled>
- <IsFocused>0</IsFocused>
- <SpeakerPosition><Position><X>0</X><Y>0</Y><Z>0</Z></Position></SpeakerPosition>
- <SessionFontID>0</SessionFontID>
- </Event>
- */
- // We don't need to process this, but we also shouldn't warn on it, since that confuses people.
- }
- else if (!stricmp(eventTypeCstr, "SessionGroupRemovedEvent"))
- {
- // We don't need to process this, but we also shouldn't warn on it, since that confuses people.
- }
- else if (!stricmp(eventTypeCstr, "VoiceServiceConnectionStateChangedEvent"))
- {
- LLVivoxVoiceClient::getInstance()->voiceServiceConnectionStateChangedEvent(statusCode, statusString, mBuildID);
- }
- else if (!stricmp(eventTypeCstr, "AudioDeviceHotSwapEvent"))
- {
- /*
- <Event type = "AudioDeviceHotSwapEvent">
- <EventType>RenderDeviceChanged< / EventType>
- <RelevantDevice>
- <Device>Speakers(Turtle Beach P11 Headset)< / Device>
- <DisplayName>Speakers(Turtle Beach P11 Headset)< / DisplayName>
- <Type>SpecificDevice< / Type>
- < / RelevantDevice>
- < / Event>
- */
- // an audio device was removed or added, fetch and update the local list of audio devices.
- LLVivoxVoiceClient::getInstance()->getCaptureDevicesSendMessage();
- LLVivoxVoiceClient::getInstance()->getRenderDevicesSendMessage();
- }
- else
- {
- LL_WARNS("VivoxProtocolParser") << "Unknown event type " << eventTypeString << LL_ENDL;
- }
- }
- else
- {
- const char *actionCstr = actionString.c_str();
- LL_DEBUGS("LowVoice") << actionCstr << LL_ENDL;
-
- if (!stricmp(actionCstr, "Session.Set3DPosition.1"))
- {
- // We don't need to process these
- }
- else if (!stricmp(actionCstr, "Connector.Create.1"))
- {
- LLVivoxVoiceClient::getInstance()->connectorCreateResponse(statusCode, statusString, connectorHandle, versionID);
- }
- else if (!stricmp(actionCstr, "Account.Login.1"))
- {
- LLVivoxVoiceClient::getInstance()->loginResponse(statusCode, statusString, accountHandle, numberOfAliases);
- }
- else if (!stricmp(actionCstr, "Session.Create.1"))
- {
- LLVivoxVoiceClient::getInstance()->sessionCreateResponse(requestId, statusCode, statusString, sessionHandle);
- }
- else if (!stricmp(actionCstr, "SessionGroup.AddSession.1"))
- {
- LLVivoxVoiceClient::getInstance()->sessionGroupAddSessionResponse(requestId, statusCode, statusString, sessionHandle);
- }
- else if (!stricmp(actionCstr, "Session.Connect.1"))
- {
- LLVivoxVoiceClient::getInstance()->sessionConnectResponse(requestId, statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.Logout.1"))
- {
- LLVivoxVoiceClient::getInstance()->logoutResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Connector.InitiateShutdown.1"))
- {
- LLVivoxVoiceClient::getInstance()->connectorShutdownResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.GetSessionFonts.1"))
- {
- LLVivoxVoiceClient::getInstance()->accountGetSessionFontsResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Account.GetTemplateFonts.1"))
- {
- LLVivoxVoiceClient::getInstance()->accountGetTemplateFontsResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Aux.SetVadProperties.1"))
- {
- // both values of statusCode (old and more recent) indicate valid requests
- if (statusCode != 0 && statusCode != 200)
- {
- LL_WARNS("Voice") << "Aux.SetVadProperties.1 request failed: "
- << "statusCode: " << statusCode
- << " and "
- << "statusString: " << statusString
- << LL_ENDL;
- }
- }
- /*
- else if (!stricmp(actionCstr, "Account.ChannelGetList.1"))
- {
- LLVoiceClient::getInstance()->channelGetListResponse(statusCode, statusString);
- }
- else if (!stricmp(actionCstr, "Connector.AccountCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.MuteLocalMic.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.MuteLocalSpeaker.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.SetLocalMicVolume.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Connector.SetLocalSpeakerVolume.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.ListenerSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.SpeakerSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.AudioSourceSetPosition.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Session.GetChannelParticipants.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelUpdate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelDelete.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelCreateAndInvite.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderCreate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderUpdate.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelFolderDelete.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelAddModerator.1"))
- {
-
- }
- else if (!stricmp(actionCstr, "Account.ChannelDeleteModerator.1"))
- {
-
- }
- */
- }
-}
-
-LLVivoxSecurity::LLVivoxSecurity()
-{
- // This size is an arbitrary choice; Vivox does not care
- // Use a multiple of three so that there is no '=' padding in the base64 (purely an esthetic choice)
- #define VIVOX_TOKEN_BYTES 9
- U8 random_value[VIVOX_TOKEN_BYTES];
-
- for (int b = 0; b < VIVOX_TOKEN_BYTES; b++)
- {
- random_value[b] = ll_rand() & 0xff;
- }
- mConnectorHandle = LLBase64::encode(random_value, VIVOX_TOKEN_BYTES);
-
- for (int b = 0; b < VIVOX_TOKEN_BYTES; b++)
- {
- random_value[b] = ll_rand() & 0xff;
- }
- mAccountHandle = LLBase64::encode(random_value, VIVOX_TOKEN_BYTES);
-}
-
-LLVivoxSecurity::~LLVivoxSecurity()
-{
-}
-
-bool LLVivoxVoiceP2PIncomingCall::answerInvite() { return LLVivoxVoiceClient::getInstance()->answerInvite(mCallInfo["session_handle"]); }
-
-void LLVivoxVoiceP2PIncomingCall::declineInvite() { LLVivoxVoiceClient::getInstance()->declineInvite(mCallInfo["session_handle"]); }
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
deleted file mode 100644
index 3167705528..0000000000
--- a/indra/newview/llvoicevivox.h
+++ /dev/null
@@ -1,1093 +0,0 @@
-/**
- * @file llvoicevivox.h
- * @brief Declaration of LLDiamondwareVoiceClient class which is the interface to the voice client process.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-#ifndef LL_VOICE_VIVOX_H
-#define LL_VOICE_VIVOX_H
-
-class LLVOAvatar;
-class LLVivoxProtocolParser;
-
-#include "lliopipe.h"
-#include "llpumpio.h"
-#include "llchainio.h"
-#include "lliosocket.h"
-#include "v3math.h"
-#include "llframetimer.h"
-#include "llviewerregion.h"
-#include "llcallingcard.h" // for LLFriendObserver
-#include "lleventcoro.h"
-#include "llcoros.h"
-#include <queue>
-
-#ifdef LL_USESYSTEMLIBS
-# include "expat.h"
-#else
-# include "expat/expat.h"
-#endif
-#include "llvoiceclient.h"
-
-class LLAvatarName;
-class LLVivoxVoiceClientMuteListObserver;
-
-extern const std::string VIVOX_VOICE_SERVER_TYPE;
-
-class LLVivoxVoiceP2PIncomingCall : public LLVoiceP2PIncomingCallInterface
-{
- public:
- LLVivoxVoiceP2PIncomingCall(const LLSD& call_info) : mCallInfo(call_info) {}
- ~LLVivoxVoiceP2PIncomingCall() override {}
-
- bool answerInvite() override;
- void declineInvite() override;
-
- protected:
- LLSD mCallInfo;
-};
-
-class LLVivoxVoiceClient : public LLSingleton<LLVivoxVoiceClient>,
- virtual public LLVoiceModuleInterface,
- virtual public LLVoiceEffectInterface,
- virtual public LLVoiceP2POutgoingCallInterface
-{
- LLSINGLETON(LLVivoxVoiceClient);
- LOG_CLASS(LLVivoxVoiceClient);
- virtual ~LLVivoxVoiceClient();
-
-public:
- /// @name LLVoiceModuleInterface virtual implementations
- /// @see LLVoiceModuleInterface
- //@{
- void init(LLPumpIO *pump) override; // Call this once at application startup (creates connector)
- void terminate() override; // Call this to clean up during shutdown
-
- const LLVoiceVersionInfo& getVersion() override;
-
- void updateSettings() override; // call after loading settings and whenever they change
-
- // Returns true if vivox has successfully logged in and is not in error state
- bool isVoiceWorking() const override;
-
- void setHidden(bool hidden) override; // virtual
-
- /////////////////////
- /// @name Tuning
- //@{
- void tuningStart() override;
- void tuningStop() override;
- bool inTuningMode() override;
-
- void tuningSetMicVolume(float volume) override;
- void tuningSetSpeakerVolume(float volume) override;
- float tuningGetEnergy(void) override;
-
- //@}
-
- /////////////////////
- /// @name Devices
- //@{
- // This returns true when it's safe to bring up the "device settings" dialog in the prefs.
- // i.e. when the daemon is running and connected, and the device lists are populated.
- bool deviceSettingsAvailable() override;
- bool deviceSettingsUpdated() override; //return if the list has been updated and never fetched, only to be called from the voicepanel.
-
- // Requery the vivox daemon for the current list of input/output devices.
- // If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed
- // (use this if you want to know when it's done).
- // If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim.
- void refreshDeviceLists(bool clearCurrentList = true) override;
-
- void setCaptureDevice(const std::string& name) override;
- void setRenderDevice(const std::string& name) override;
-
- LLVoiceDeviceList& getCaptureDevices() override;
- LLVoiceDeviceList& getRenderDevices() override;
- //@}
-
- void getParticipantList(std::set<LLUUID> &participants) override;
- bool isParticipant(const LLUUID& speaker_id) override;
-
- // Send a text message to the specified user, initiating the session if necessary.
- // virtual bool sendTextMessage(const LLUUID& participant_id, const std::string& message) const {return false;};
-
- // Returns true if calling back the session URI after the session has closed is possible.
- // Currently this will be false only for PSTN P2P calls.
- // NOTE: this will return true if the session can't be found.
- bool isSessionCallBackPossible(const LLUUID &session_id) override;
-
- // Returns true if the session can accepte text IM's.
- // Currently this will be false only for PSTN P2P calls.
- // NOTE: this will return true if the session can't be found.
- bool isSessionTextIMPossible(const LLUUID &session_id) override;
-
- ////////////////////////////
- /// @name Channel stuff
- //@{
- // returns true iff the user is currently in a proximal (local spatial) channel.
- // Note that gestures should only fire if this returns true.
- bool inProximalChannel() override;
-
- void setNonSpatialChannel(const LLSD& channelInfo,
- bool notify_on_first_join,
- bool hangup_on_last_leave) override;
-
- bool setSpatialChannel(const LLSD& channelInfo) override;
-
- void leaveNonSpatialChannel() override;
-
- void processChannels(bool process) override;
-
- void leaveChannel(void);
-
- bool isCurrentChannel(const LLSD &channelInfo) override;
- bool compareChannels(const LLSD &channelInfo1, const LLSD &channelInfo2) override;
-
- //@}
-
-
- //////////////////////////
- /// @name LLVoiceP2POutgoingCallInterface
- //@{
- // start a voice channel with the specified user
- void callUser(const LLUUID &uuid) override;
- void hangup() override;
-
- //@}
-
- LLVoiceP2POutgoingCallInterface *getOutgoingCallInterface() override { return this; }
-
- LLVoiceP2PIncomingCallInterfacePtr getIncomingCallInterface(const LLSD &voice_call_info) override;
-
- bool answerInvite(const std::string &sessionHandle);
- void declineInvite(const std::string &sessionHandle);
-
- /////////////////////////
- /// @name Volume/gain
- //@{
- void setVoiceVolume(F32 volume) override;
- void setMicGain(F32 volume) override;
- //@}
-
- /////////////////////////
- /// @name enable disable voice and features
- //@{
- void setVoiceEnabled(bool enabled) override;
- void setMuteMic(bool muted) override; // Set the mute state of the local mic.
- //@}
-
- //////////////////////////
- /// @name nearby speaker accessors
- //@{
- std::string getDisplayName(const LLUUID& id) override;
- bool isParticipantAvatar(const LLUUID &id) override;
- bool getIsSpeaking(const LLUUID& id) override;
- bool getIsModeratorMuted(const LLUUID& id) override;
- F32 getCurrentPower(const LLUUID& id) override; // "power" is related to "amplitude" in a defined way. I'm just not sure what the formula is...
- F32 getUserVolume(const LLUUID& id) override;
- void setUserVolume(const LLUUID& id, F32 volume) override; // set's volume for specified agent, from 0-1 (where .5 is nominal)
- //@}
-
- // authorize the user
- void userAuthorized(const std::string& user_id,
- const LLUUID &agentID) override;
-
- //////////////////////////////
- /// @name Status notification
- //@{
- void addObserver(LLVoiceClientStatusObserver* observer) override;
- void removeObserver(LLVoiceClientStatusObserver* observer) override;
- void addObserver(LLFriendObserver* observer) override;
- void removeObserver(LLFriendObserver* observer) override;
- void addObserver(LLVoiceClientParticipantObserver* observer) override;
- void removeObserver(LLVoiceClientParticipantObserver* observer) override;
- //@}
-
- std::string sipURIFromID(const LLUUID &id) const override;
- LLSD getP2PChannelInfoTemplate(const LLUUID& id) const override;
- //@}
-
- /// @name LLVoiceEffectInterface virtual implementations
- /// @see LLVoiceEffectInterface
- //@{
-
- //////////////////////////
- /// @name Accessors
- //@{
- bool setVoiceEffect(const LLUUID& id) override;
- const LLUUID getVoiceEffect() override;
- LLSD getVoiceEffectProperties(const LLUUID& id) override;
-
- void refreshVoiceEffectLists(bool clear_lists) override;
- const voice_effect_list_t& getVoiceEffectList() const override;
- const voice_effect_list_t& getVoiceEffectTemplateList() const override;
- //@}
-
- //////////////////////////////
- /// @name Status notification
- //@{
- void addObserver(LLVoiceEffectObserver* observer) override;
- void removeObserver(LLVoiceEffectObserver* observer) override;
- //@}
-
- //////////////////////////////
- /// @name Effect preview buffer
- //@{
- void enablePreviewBuffer(bool enable) override;
- void recordPreviewBuffer() override;
- void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null) override;
- void stopPreviewBuffer() override;
-
- bool isPreviewRecording() override;
- bool isPreviewPlaying() override;
- //@}
-
- //@}
-
- bool onCheckVoiceEffect(const std::string& voice_effect_name);
- void onClickVoiceEffect(const std::string& voice_effect_name);
-
-protected:
- //////////////////////
- // Vivox Specific definitions
-
- friend class LLVivoxVoiceClientMuteListObserver;
- friend class LLVivoxVoiceClientFriendsObserver;
-
-
- enum streamState
- {
- streamStateUnknown = 0,
- streamStateIdle = 1,
- streamStateConnected = 2,
- streamStateRinging = 3,
- streamStateConnecting = 6, // same as Vivox session_media_connecting enum
- streamStateDisconnecting = 7, //Same as Vivox session_media_disconnecting enum
- };
-
- struct participantState
- {
- public:
- participantState(const std::string &uri);
-
- bool updateMuteState(); // true if mute state has changed
- bool isAvatar();
-
- std::string mURI;
- LLUUID mAvatarID;
- std::string mAccountName;
- std::string mDisplayName;
- LLFrameTimer mSpeakingTimeout;
- F32 mLastSpokeTimestamp;
- F32 mPower;
- F32 mVolume;
- std::string mGroupID;
- int mUserVolume;
- bool mPTT;
- 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 mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed)
- bool mAvatarIDValid;
- bool mIsSelf;
- };
- typedef std::shared_ptr<participantState> participantStatePtr_t;
- typedef std::weak_ptr<participantState> participantStateWptr_t;
-
- typedef std::map<const std::string, participantStatePtr_t> participantMap;
- typedef std::map<const LLUUID, participantStatePtr_t> participantUUIDMap;
-
- struct sessionState
- {
- public:
- typedef std::shared_ptr<sessionState> ptr_t;
- typedef std::weak_ptr<sessionState> wptr_t;
-
- typedef std::function<void(const ptr_t &)> sessionFunc_t;
-
- static ptr_t createSession();
- ~sessionState();
-
- LLSD getVoiceChannelInfo();
-
- participantStatePtr_t addParticipant(const std::string &uri);
- void removeParticipant(const participantStatePtr_t &participant);
- void removeAllParticipants();
-
- participantStatePtr_t findParticipant(const std::string &uri);
- participantStatePtr_t findParticipantByID(const LLUUID& id);
-
- static ptr_t matchSessionByHandle(const std::string &handle);
- static ptr_t matchCreatingSessionByURI(const std::string &uri);
- static ptr_t matchSessionByURI(const std::string &uri);
- static ptr_t matchSessionByParticipant(const LLUUID &participant_id);
-
- bool isCallBackPossible();
- bool isTextIMPossible();
- bool isSpatial() { return mIsSpatial; }
-
- static void for_each(sessionFunc_t func);
-
- std::string mHandle;
- std::string mGroupHandle;
- std::string mSIPURI;
- std::string mAlias;
- std::string mName;
- std::string mAlternateSIPURI;
- std::string mHash; // Channel password
- std::string mErrorStatusString;
- std::queue<std::string> mTextMsgQueue;
-
- LLUUID mIMSessionID;
- LLUUID mCallerID;
- int mErrorStatusCode;
- int mMediaStreamState;
- bool mCreateInProgress; // True if a Session.Create has been sent for this session and no response has been received yet.
- bool mMediaConnectInProgress; // True if a Session.MediaConnect has been sent for this session and no response has been received yet.
- bool mVoiceInvitePending; // True if a voice invite is pending for this session (usually waiting on a name lookup)
- bool mTextInvitePending; // True if a text invite is pending for this session (usually waiting on a name lookup)
- bool mSynthesizedCallerID; // True if the caller ID is a hash of the SIP URI -- this means we shouldn't do a name lookup.
- bool mIsChannel; // True for both group and spatial channels (false for p2p, PSTN)
- bool mIsSpatial; // True for spatial channels
- bool mIsP2P;
- bool mIncoming;
- bool mVoiceActive;
- bool mReconnect; // Whether we should try to reconnect to this session if it's dropped
-
- // 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 mParticipantsChanged;
- participantMap mParticipantsByURI;
- participantUUIDMap mParticipantsByUUID;
-
- LLUUID mVoiceFontID;
-
- static void VerifySessions();
-
- private:
- sessionState();
-
- static std::set<wptr_t, std::owner_less<wptr_t>> mSession; // canonical list of outstanding sessions.
- std::set<wptr_t>::iterator mMyIterator; // used for delete
-
- static void for_eachPredicate(const wptr_t &a, sessionFunc_t func);
-
- static bool testByHandle(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string handle);
- static bool testByCreatingURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri);
- static bool testBySIPOrAlterateURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri);
- static bool testByCallerId(const LLVivoxVoiceClient::sessionState::wptr_t &a, LLUUID participantId);
-
- };
- typedef std::shared_ptr<sessionState> sessionStatePtr_t;
-
- typedef std::map<std::string, sessionStatePtr_t> sessionMap;
-
- ///////////////////////////////////////////////////////
- // Private Member Functions
- //////////////////////////////////////////////////////
-
-
-
- //////////////////////////////
- /// @name TVC/Server management and communication
- //@{
- // Call this if the connection to the daemon terminates unexpectedly. It will attempt to reset everything and relaunch.
- void daemonDied();
-
- // Call this if we're just giving up on voice (can't provision an account, etc.). It will clean up and go away.
- void giveUp();
-
- // write to the tvc
- bool writeString(const std::string &str);
-
- void connectorCreate();
- void connectorShutdown();
- void closeSocket(void);
-
-// void requestVoiceAccountProvision(S32 retries = 3);
- void setLoginInfo(
- const std::string& account_name,
- const std::string& password,
- const std::string& voice_sip_uri_hostname,
- const std::string& voice_account_server_uri);
- void loginSendMessage();
- void logout();
- void logoutSendMessage();
-
-
- //@}
-
- //------------------------------------
- // tuning
-
- void tuningRenderStartSendMessage(const std::string& name, bool loop);
- void tuningRenderStopSendMessage();
-
- void tuningCaptureStartSendMessage(int duration);
- void tuningCaptureStopSendMessage();
-
- //----------------------------------
- // devices
- void clearCaptureDevices();
- void addCaptureDevice(const LLVoiceDevice& device);
- void clearRenderDevices();
- void setDevicesListUpdated(bool state);
- void addRenderDevice(const LLVoiceDevice& device);
- void buildSetAudioDevices(std::ostringstream &stream);
-
- void getCaptureDevicesSendMessage();
- void getRenderDevicesSendMessage();
-
- // local audio updates, mic mute, speaker mute, mic volume and speaker volumes
- void sendLocalAudioUpdates();
-
- /////////////////////////////
- // Response/Event handlers
- void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID);
- void loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases);
- void sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle);
- void sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle);
- void sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString);
- void logoutResponse(int statusCode, std::string &statusString);
- 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 sessionAddedEvent(std::string &uriString, std::string &alias, std::string &sessionHandle, std::string &sessionGroupHandle, bool isChannel, bool incoming, std::string &nameString, std::string &applicationString);
- void sessionGroupAddedEvent(std::string &sessionGroupHandle);
- void sessionRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle);
- void participantAddedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString, std::string &displayNameString, int participantType);
- void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString);
- void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy);
- void voiceServiceConnectionStateChangedEvent(int statusCode, std::string &statusString, std::string &build_id);
- void auxAudioPropertiesEvent(F32 energy);
- void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString);
- void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string &notificationType);
-
- void muteListChanged();
-
- /////////////////////////////
- // VAD changes
- // disable auto-VAD and configure VAD parameters explicitly
- void setupVADParams(unsigned int vad_auto, unsigned int vad_hangover, unsigned int vad_noise_floor, unsigned int vad_sensitivity);
- void onVADSettingsChange();
-
- /////////////////////////////
- // Sending updates of current state
- void updatePosition(void);
- void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot);
- void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot);
- bool channelFromRegion(LLViewerRegion *region, std::string &name);
-
- void setEarLocation(S32 loc);
-
-
- /////////////////////////////
- // Accessors for data related to nearby speakers
-
- // MBW -- XXX -- Not sure how to get this data out of the TVC
- bool getUsingPTT(const LLUUID& id);
- std::string getGroupID(const LLUUID& id); // group ID if the user is in group chat (empty string if not applicable)
-
- /////////////////////////////
- // Recording controls
- void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200);
- void recordingLoopSave(const std::string& filename);
- void recordingStop();
-
- // Playback controls
- void filePlaybackStart(const std::string& filename);
- void filePlaybackStop();
- void filePlaybackSetPaused(bool paused);
- void filePlaybackSetMode(bool vox = false, float speed = 1.0f);
-
- participantStatePtr_t findParticipantByID(const LLUUID& id);
-
-
-#if 0
- ////////////////////////////////////////
- // voice sessions.
- typedef std::set<sessionStatePtr_t> sessionSet;
-
- typedef sessionSet::iterator sessionIterator;
- sessionIterator sessionsBegin(void);
- sessionIterator sessionsEnd(void);
-#endif
-
- sessionStatePtr_t findSession(const std::string &handle);
- sessionStatePtr_t findSessionBeingCreatedByURI(const std::string &uri);
- sessionStatePtr_t findSession(const LLUUID &participant_id);
-
- sessionStatePtr_t addSession(const std::string &uri, const std::string &handle = std::string());
- void clearSessionHandle(const sessionStatePtr_t &session);
- void setSessionHandle(const sessionStatePtr_t &session, const std::string &handle);
- void setSessionURI(const sessionStatePtr_t &session, const std::string &uri);
- void deleteSession(const sessionStatePtr_t &session);
- void deleteAllSessions(void);
-
- void verifySessionState(void);
-
- void joinedAudioSession(const sessionStatePtr_t &session);
- void leftAudioSession(const sessionStatePtr_t &session);
-
- // This is called in several places where the session _may_ need to be deleted.
- // It contains logic for whether to delete the session or keep it around.
- void reapSession(const sessionStatePtr_t &session);
-
- // Returns true if the session seems to indicate we've moved to a region on a different voice server
- bool sessionNeedsRelog(const sessionStatePtr_t &session);
-
-
- //////////////////////////////////////
- // buddy list stuff, needed for SLIM later
- struct buddyListEntry
- {
- buddyListEntry(const std::string &uri);
- std::string mURI;
- std::string mDisplayName;
- LLUUID mUUID;
- bool mOnlineSL;
- bool mOnlineSLim;
- bool mCanSeeMeOnline;
- bool mHasBlockListEntry;
- bool mHasAutoAcceptListEntry;
- bool mNameResolved;
- bool mInSLFriends;
- bool mInVivoxBuddies;
- };
-
- typedef std::map<std::string, buddyListEntry*> buddyListMap;
-
- /////////////////////////////
- // session control messages
-
- void accountListBlockRulesSendMessage();
- void accountListAutoAcceptRulesSendMessage();
-
- void sessionGroupCreateSendMessage();
- void sessionCreateSendMessage(const sessionStatePtr_t &session, bool startAudio = true, bool startText = false);
- void sessionGroupAddSessionSendMessage(const sessionStatePtr_t &session, bool startAudio = true, bool startText = false);
- void sessionMediaConnectSendMessage(const sessionStatePtr_t &session); // just joins the audio session
- void sessionTextConnectSendMessage(const sessionStatePtr_t &session); // just joins the text session
- void sessionTerminateSendMessage(const sessionStatePtr_t &session);
- void sessionGroupTerminateSendMessage(const sessionStatePtr_t &session);
- void sessionMediaDisconnectSendMessage(const sessionStatePtr_t &session);
- // void sessionTextDisconnectSendMessage(sessionState *session);
-
-
-
- // Pokes the state machine to leave the audio session next time around.
- void sessionTerminate();
-
- // Pokes the state machine to shut down the connector and restart it.
- void requestRelog();
-
- // Does the actual work to get out of the audio session
- void leaveAudioSession();
-
- friend class LLVivoxVoiceClientCapResponder;
-
-
- void lookupName(const LLUUID &id);
- void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
- void avatarNameResolved(const LLUUID &id, const std::string &name);
- static void predAvatarNameResolution(const LLVivoxVoiceClient::sessionStatePtr_t &session, LLUUID id, std::string name);
-
- boost::signals2::connection mAvatarNameCacheConnection;
-
- /////////////////////////////
- // 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;
-
- // Coroutine support methods
- //---
- void voiceControlCoro();
- void voiceControlStateMachine(S32 &coro_state);
-
- bool endAndDisconnectSession();
-
- bool callbackEndDaemon(const LLSD& data);
- bool startAndLaunchDaemon();
- bool provisionVoiceAccount();
- bool establishVoiceConnection();
- bool breakVoiceConnection(bool wait);
- bool loginToVivox();
- void logoutOfVivox(bool wait);
- bool retrieveVoiceFonts();
-
- bool requestParcelVoiceInfo();
-
- bool addAndJoinSession(const sessionStatePtr_t &nextSession);
- bool terminateAudioSession(bool wait);
-
- bool waitForChannel();
- bool runSession(const sessionStatePtr_t &session);
-
- void recordingAndPlaybackMode();
- int voiceRecordBuffer();
- int voicePlaybackBuffer();
-
- bool performMicTuning();
- //---
- /// Clean up objects created during a voice session.
- void cleanUp();
-
- bool mSessionTerminateRequested;
- bool mRelogRequested;
- // Number of times (in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine().
- // The larger it is the greater is possibility there is a problem with connection to voice server.
- // Introduced while fixing EXT-4313.
- int mSpatialJoiningNum;
-
- static void idle(void *user_data);
-
- LLHost mDaemonHost;
- LLSocket::ptr_t mSocket;
-
- // We should kill the voice daemon in case of connection alert
- bool mTerminateDaemon;
-
- friend class LLVivoxProtocolParser;
-
- std::string mAccountName;
- std::string mAccountPassword;
- std::string mAccountDisplayName;
-
- bool mTuningMode;
- float mTuningEnergy;
- std::string mTuningAudioFile;
- int mTuningMicVolume;
- bool mTuningMicVolumeDirty;
- int mTuningSpeakerVolume;
- bool mTuningSpeakerVolumeDirty;
- bool mDevicesListUpdated; // set to true when the device list has been updated
- // and false when the panelvoicedevicesettings has queried for an update status.
-
- std::string mSpatialSessionURI;
- std::string mSpatialSessionCredentials;
-
- std::string mMainSessionGroupHandle; // handle of the "main" session group.
-
- std::string mChannelName; // Name of the channel to be looked up
- sessionStatePtr_t mAudioSession; // Session state for the current audio session
-
- sessionStatePtr_t mNextAudioSession; // Session state for the audio session we're trying to join
-
- S32 mCurrentParcelLocalID; // Used to detect parcel boundary crossings
- std::string mCurrentRegionName; // Used to detect parcel boundary crossings
-
- bool mConnectorEstablished; // set by "Create Connector" response
- bool mAccountLoggedIn; // set by login message
- int mNumberOfAliases;
- U32 mCommandCookie;
-
- std::string mVoiceAccountServerURI;
- std::string mVoiceSIPURIHostName;
-
- int mLoginRetryCount;
-
- sessionMap mSessionsByHandle; // Active sessions, indexed by session handle. Sessions which are being initiated may not be in this map.
-#if 0
- sessionSet mSessions; // All sessions, not indexed. This is the canonical session list.
-#endif
-
- bool mBuddyListMapPopulated;
- bool mBlockRulesListReceived;
- bool mAutoAcceptRulesListReceived;
- buddyListMap mBuddyListMap;
-
- LLVoiceDeviceList mCaptureDevices;
- LLVoiceDeviceList mRenderDevices;
-
- std::string mCaptureDevice;
- std::string mRenderDevice;
- bool mCaptureDeviceDirty;
- bool mRenderDeviceDirty;
-
- bool mIsInitialized;
- bool mShutdownComplete;
-
- bool checkParcelChanged(bool update = false);
- bool switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
- void joinSession(const sessionStatePtr_t &session);
-
- std::string nameFromID(const LLUUID &id) const;
- bool IDFromName(const std::string name, LLUUID &uuid);
- std::string sipURIFromAvatar(LLVOAvatar *avatar);
- std::string sipURIFromName(std::string &name);
-
- // Returns the name portion of the SIP URI if the string looks vaguely like a SIP URI, or an empty string if not.
- std::string nameFromsipURI(const std::string &uri);
-
- bool inSpatialChannel(void);
- LLSD getAudioSessionChannelInfo();
- std::string getAudioSessionHandle();
-
- void sendPositionAndVolumeUpdate(void);
-
- void sendCaptureAndRenderDevices();
- void buildSetCaptureDevice(std::ostringstream &stream);
- void buildSetRenderDevice(std::ostringstream &stream);
-
-
- void sendFriendsListUpdates();
-
-#if 0
- // start a text IM session with the specified user
- // This will be asynchronous, the session may be established at a future time.
- sessionStatePtr_t startUserIMSession(const LLUUID& uuid);
-#endif
-
- void enforceTether(void);
-
- bool mSpatialCoordsDirty;
-
- LLVector3d mCameraPosition;
- LLVector3d mCameraRequestedPosition;
- LLVector3 mCameraVelocity;
- LLMatrix3 mCameraRot;
-
- LLVector3d mAvatarPosition;
- LLVector3 mAvatarVelocity;
- LLQuaternion mAvatarRot;
-
- bool mMuteMic;
- bool mMuteMicDirty;
- bool mHidden; //Set to true during teleport to hide the agent's position.
-
- // Set to true when the friends list is known to have changed.
- bool mFriendsListDirty;
-
- enum
- {
- earLocCamera = 0, // ear at camera
- earLocAvatar, // ear at avatar
- earLocMixed // ear at avatar location/camera direction
- };
-
- S32 mEarLocation;
-
- bool mSpeakerVolumeDirty;
- bool mSpeakerMuteDirty;
- int mSpeakerVolume;
-
- int mMicVolume;
- bool mMicVolumeDirty;
-
- bool mVoiceEnabled;
- bool mProcessChannels;
- bool mWriteInProgress;
- std::string mWriteString;
- size_t mWriteOffset;
-
- typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t;
- observer_set_t mParticipantObservers;
-
- void notifyParticipantObservers();
-
- typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t;
- status_observer_set_t mStatusObservers;
-
- void notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status);
-
- 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(const sessionStatePtr_t &session);
-
- void updateVoiceMorphingMenu();
- 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;
- };
-
- 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;
- bool mIsInTuningMode;
- bool mIsInChannel;
- bool mIsJoiningSession;
- bool mIsWaitingForFonts;
- bool mIsLoggingIn;
- bool mIsLoggedIn;
- bool mIsProcessingChannels;
- bool mIsCoroutineActive;
-
- // This variables can last longer than vivox in coroutines so we need them as static
- static bool sShuttingDown;
- static bool sConnected;
- static LLPumpIO* sPump;
-
- LLEventMailDrop mVivoxPump;
-};
-
-
-/**
- * @class LLVivoxProtocolParser
- * @brief This class helps construct new LLIOPipe specializations
- * @see LLIOPipe
- *
- * THOROUGH_DESCRIPTION
- */
-class LLVivoxProtocolParser : public LLIOPipe
-{
- LOG_CLASS(LLVivoxProtocolParser);
-public:
- LLVivoxProtocolParser();
- virtual ~LLVivoxProtocolParser();
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
- std::string mInput;
-
- // Expat control members
- XML_Parser parser;
- int responseDepth;
- bool ignoringTags;
- bool isEvent;
- int ignoreDepth;
-
- // Members for processing responses. The values are transient and only valid within a call to processResponse().
- int returnCode;
- int statusCode;
- std::string statusString;
- std::string requestId;
- std::string actionString;
- std::string connectorHandle;
- std::string versionID;
- std::string mBuildID;
- std::string accountHandle;
- std::string sessionHandle;
- std::string sessionGroupHandle;
- std::string alias;
- std::string applicationString;
-
- // Members for processing events. The values are transient and only valid within a call to processResponse().
- std::string eventTypeString;
- int state;
- std::string uriString;
- bool isChannel;
- bool incoming;
- bool enabled;
- std::string nameString;
- std::string audioMediaString;
- std::string deviceString;
- std::string displayNameString;
- int participantType;
- bool isLocallyMuted;
- bool isModeratorMuted;
- bool isSpeaking;
- int volume;
- F32 energy;
- std::string messageHeader;
- std::string messageBody;
- std::string notificationType;
- bool hasText;
- bool hasAudio;
- bool hasVideo;
- bool terminated;
- std::string blockMask;
- std::string presenceOnly;
- std::string autoAcceptMask;
- std::string autoAddAsBuddy;
- 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;
- bool accumulateText;
-
- void reset();
-
- void processResponse(std::string tag);
-
- static void XMLCALL ExpatStartTag(void *data, const char *el, const char **attr);
- static void XMLCALL ExpatEndTag(void *data, const char *el);
- static void XMLCALL ExpatCharHandler(void *data, const XML_Char *s, int len);
-
- 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);
-
-};
-
-class LLVivoxSecurity : public LLSingleton<LLVivoxSecurity>
-{
- LLSINGLETON(LLVivoxSecurity);
- virtual ~LLVivoxSecurity();
-
- public:
- std::string connectorHandle() { return mConnectorHandle; };
- std::string accountHandle() { return mAccountHandle; };
-
- private:
- std::string mConnectorHandle;
- std::string mAccountHandle;
-};
-
-class LLVoiceVivoxStats : public LLSingleton<LLVoiceVivoxStats>
-{
- LLSINGLETON(LLVoiceVivoxStats);
- LOG_CLASS(LLVoiceVivoxStats);
- virtual ~LLVoiceVivoxStats();
-
- private:
- F64SecondsImplicit mStartTime;
-
- U32 mConnectCycles;
-
- F64 mConnectTime;
- U32 mConnectAttempts;
-
- F64 mProvisionTime;
- U32 mProvisionAttempts;
-
- F64 mEstablishTime;
- U32 mEstablishAttempts;
-
- public:
-
- void reset();
- void connectionAttemptStart();
- void connectionAttemptEnd(bool success);
- void provisionAttemptStart();
- void provisionAttemptEnd(bool success);
- void establishAttemptStart();
- void establishAttemptEnd(bool success);
- LLSD read();
-};
-
-#endif //LL_VIVOX_VOICE_CLIENT_H
-
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index 333046adce..59e634b130 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -2342,12 +2342,6 @@ void LLWebRTCVoiceClient::avatarNameResolved(const LLUUID &id, const std::string
sessionState::for_each(boost::bind(predAvatarNameResolution, _1, id, name));
}
-// Leftover from vivox PTSN
-std::string LLWebRTCVoiceClient::sipURIFromID(const LLUUID& id) const
-{
- return id.asString();
-}
-
LLSD LLWebRTCVoiceClient::getP2PChannelInfoTemplate(const LLUUID& id) const
{
return LLSD();
diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h
index 8efbd1778f..be384f0de0 100644
--- a/indra/newview/llvoicewebrtc.h
+++ b/indra/newview/llvoicewebrtc.h
@@ -87,7 +87,6 @@ public:
// Returns true if WebRTC has successfully logged in and is not in error state
bool isVoiceWorking() const override;
- std::string sipURIFromID(const LLUUID &id) const override;
LLSD getP2PChannelInfoTemplate(const LLUUID& id) const override;
void setHidden(bool hidden) override; // virtual
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index c33f4f140a..8e59c26316 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -576,14 +576,6 @@ class Windows_x86_64_Manifest(ViewerManifest):
self.path_optional("vcruntime140_1.dll")
self.path_optional("vcruntime140_threads.dll")
- # SLVoice executable
- with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
- self.path("SLVoice.exe")
-
- # Vivox libraries
- self.path("vivoxsdk_x64.dll")
- self.path("ortp_x64.dll")
-
# BugSplat
if self.args.get('bugsplat'):
self.path("BsSndRpt64.exe")
@@ -1139,16 +1131,6 @@ class Darwin_x86_64_Manifest(ViewerManifest):
# Need to get the llcommon dll from any of the build directories as well.
libfile_parent = self.get_dst_prefix()
dylibs=[]
- # SLVoice executable
- with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
- self.path("SLVoice")
-
- # Vivox libraries
- for libfile in (
- 'libortp.dylib',
- 'libvivoxsdk.dylib',
- ):
- self.path2basename(relpkgdir, libfile)
# Discord social SDK
if self.args['discord'] == 'ON':
@@ -1475,7 +1457,6 @@ class Linux_i686_Manifest(LinuxManifest):
self.path("libdirect-1.4.so.5*")
self.path("libalut.so*")
self.path("libopenal.so*")
- self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname
# KLUDGE: As of 2012-04-11, the 'fontconfig' package installs
# libfontconfig.so.1.4.4, along with symlinks libfontconfig.so.1
# and libfontconfig.so. Before we added support for library-file
@@ -1505,15 +1486,6 @@ class Linux_i686_Manifest(LinuxManifest):
print("tcmalloc files not found, skipping")
pass
- # Vivox runtimes
- with self.prefix(src=relpkgdir, dst="bin"):
- self.path("SLVoice")
- with self.prefix(src=relpkgdir, dst="lib"):
- self.path("libortp.so")
- self.path("libsndfile.so.1")
- #self.path("libvivoxoal.so.1") # no - we'll re-use the viewer's own OpenAL lib
- self.path("libvivoxsdk.so")
-
self.strip_binaries()