00001
00032 #include <boost/tokenizer.hpp>
00033
00034 #include "llviewerprecompiledheaders.h"
00035 #include "llvoiceclient.h"
00036
00037 #include "llsdutil.h"
00038
00039 #include "llvoavatar.h"
00040 #include "llbufferstream.h"
00041 #include "llfile.h"
00042 #include "expat/expat.h"
00043 #include "llcallbacklist.h"
00044 #include "llviewerregion.h"
00045 #include "llviewernetwork.h"
00046 #include "llfloateractivespeakers.h"
00047 #include "llbase64.h"
00048 #include "llviewercontrol.h"
00049 #include "llkeyboard.h"
00050 #include "viewer.h"
00051 #include "llmutelist.h"
00052 #include "llagent.h"
00053 #include "llcachename.h"
00054 #include "llimview.h"
00055 #include "llimpanel.h"
00056 #include "llparcel.h"
00057 #include "llviewerparcelmgr.h"
00058 #include "llfirstuse.h"
00059 #include "llviewerwindow.h"
00060
00061
00062 #include "apr-1/apr_base64.h"
00063
00064
00065 #include "apr-1/apr_sha1.h"
00066
00067
00068
00069 #define AGNI_LINDENS_ONLY_CHANNEL "SL"
00070 static bool sConnectingToAgni = false;
00071 F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
00072
00073 const F32 SPEAKING_TIMEOUT = 1.f;
00074
00075 const int VOICE_MAJOR_VERSION = 1;
00076 const int VOICE_MINOR_VERSION = 0;
00077
00078 LLVoiceClient *gVoiceClient = NULL;
00079
00080
00081 const F32 CONNECT_THROTTLE_SECONDS = 1.0f;
00082
00083
00084 const F32 UPDATE_THROTTLE_SECONDS = 0.1f;
00085
00086 const F32 LOGIN_RETRY_SECONDS = 10.0f;
00087 const int MAX_LOGIN_RETRIES = 12;
00088
00089 class LLViewerVoiceAccountProvisionResponder :
00090 public LLHTTPClient::Responder
00091 {
00092 public:
00093 LLViewerVoiceAccountProvisionResponder(int retries)
00094 {
00095 mRetries = retries;
00096 }
00097
00098 virtual void error(U32 status, const std::string& reason)
00099 {
00100 if ( mRetries > 0 )
00101 {
00102 if ( gVoiceClient ) gVoiceClient->requestVoiceAccountProvision(
00103 mRetries - 1);
00104 }
00105 else
00106 {
00107
00108 if ( gVoiceClient ) gVoiceClient->giveUp();
00109 }
00110 }
00111
00112 virtual void result(const LLSD& content)
00113 {
00114 if ( gVoiceClient )
00115 {
00116 gVoiceClient->login(
00117 content["username"].asString(),
00118 content["password"].asString());
00119 }
00120 }
00121
00122 private:
00123 int mRetries;
00124 };
00125
00133 class LLVivoxProtocolParser : public LLIOPipe
00134 {
00135 LOG_CLASS(LLVivoxProtocolParser);
00136 public:
00137 LLVivoxProtocolParser();
00138 virtual ~LLVivoxProtocolParser();
00139
00140 protected:
00141
00142
00144
00147 virtual EStatus process_impl(
00148 const LLChannelDescriptors& channels,
00149 buffer_ptr_t& buffer,
00150 bool& eos,
00151 LLSD& context,
00152 LLPumpIO* pump);
00154
00155 std::string mInput;
00156
00157
00158 XML_Parser parser;
00159 int responseDepth;
00160 bool ignoringTags;
00161 bool isEvent;
00162 int ignoreDepth;
00163
00164
00165 int returnCode;
00166 int statusCode;
00167 std::string statusString;
00168 std::string uuidString;
00169 std::string actionString;
00170 std::string connectorHandle;
00171 std::string accountHandle;
00172 std::string sessionHandle;
00173 std::string eventSessionHandle;
00174
00175
00176 std::string eventTypeString;
00177 int state;
00178 std::string uriString;
00179 bool isChannel;
00180 std::string nameString;
00181 std::string audioMediaString;
00182 std::string displayNameString;
00183 int participantType;
00184 bool isLocallyMuted;
00185 bool isModeratorMuted;
00186 bool isSpeaking;
00187 int volume;
00188 F32 energy;
00189
00190
00191 std::string textBuffer;
00192 bool accumulateText;
00193
00194 void reset();
00195
00196 void processResponse(std::string tag);
00197
00198 static void XMLCALL ExpatStartTag(void *data, const char *el, const char **attr);
00199 static void XMLCALL ExpatEndTag(void *data, const char *el);
00200 static void XMLCALL ExpatCharHandler(void *data, const XML_Char *s, int len);
00201
00202 void StartTag(const char *tag, const char **attr);
00203 void EndTag(const char *tag);
00204 void CharData(const char *buffer, int length);
00205
00206 };
00207
00208 LLVivoxProtocolParser::LLVivoxProtocolParser()
00209 {
00210 parser = NULL;
00211 parser = XML_ParserCreate(NULL);
00212
00213 reset();
00214 }
00215
00216 void LLVivoxProtocolParser::reset()
00217 {
00218 responseDepth = 0;
00219 ignoringTags = false;
00220 accumulateText = false;
00221 textBuffer.clear();
00222 }
00223
00224
00225 LLVivoxProtocolParser::~LLVivoxProtocolParser()
00226 {
00227 if (parser)
00228 XML_ParserFree(parser);
00229 }
00230
00231
00232 LLIOPipe::EStatus LLVivoxProtocolParser::process_impl(
00233 const LLChannelDescriptors& channels,
00234 buffer_ptr_t& buffer,
00235 bool& eos,
00236 LLSD& context,
00237 LLPumpIO* pump)
00238 {
00239 LLBufferStream istr(channels, buffer.get());
00240 std::ostringstream ostr;
00241 while (istr.good())
00242 {
00243 char buf[1024];
00244 istr.read(buf, sizeof(buf));
00245 mInput.append(buf, istr.gcount());
00246 }
00247
00248
00249
00250
00251
00252
00253 int start = 0;
00254 int delim;
00255 while((delim = mInput.find("\n\n\n", start)) != std::string::npos)
00256 {
00257
00258 if(0)
00259 {
00260 int foo = mInput.find("Set3DPosition", start);
00261 int bar = mInput.find("ParticipantPropertiesEvent", start);
00262 if(foo != std::string::npos && (foo < delim))
00263 {
00264
00265 }
00266 else if(bar != std::string::npos && (bar < delim))
00267 {
00268
00269 }
00270 else
00271 {
00272 llinfos << "parsing: " << mInput.substr(start, delim - start) << llendl;
00273 }
00274 }
00275
00276
00277 reset();
00278
00279 XML_ParserReset(parser, NULL);
00280 XML_SetElementHandler(parser, ExpatStartTag, ExpatEndTag);
00281 XML_SetCharacterDataHandler(parser, ExpatCharHandler);
00282 XML_SetUserData(parser, this);
00283 XML_Parse(parser, mInput.data() + start, delim - start, false);
00284
00285 start = delim + 3;
00286 }
00287
00288 if(start != 0)
00289 mInput = mInput.substr(start);
00290
00291
00292
00293 if(!gVoiceClient->mConnected)
00294 {
00295
00296 llinfos << "returning STATUS_STOP" << llendl;
00297 return STATUS_STOP;
00298 }
00299
00300 return STATUS_OK;
00301 }
00302
00303 void XMLCALL LLVivoxProtocolParser::ExpatStartTag(void *data, const char *el, const char **attr)
00304 {
00305 if (data)
00306 {
00307 LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
00308 object->StartTag(el, attr);
00309 }
00310 }
00311
00312
00313
00314 void XMLCALL LLVivoxProtocolParser::ExpatEndTag(void *data, const char *el)
00315 {
00316 if (data)
00317 {
00318 LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
00319 object->EndTag(el);
00320 }
00321 }
00322
00323
00324
00325 void XMLCALL LLVivoxProtocolParser::ExpatCharHandler(void *data, const XML_Char *s, int len)
00326 {
00327 if (data)
00328 {
00329 LLVivoxProtocolParser *object = (LLVivoxProtocolParser*)data;
00330 object->CharData(s, len);
00331 }
00332 }
00333
00334
00335
00336
00337 void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
00338 {
00339
00340 textBuffer.clear();
00341
00342 accumulateText = !ignoringTags;
00343
00344 if (responseDepth == 0)
00345 {
00346 isEvent = strcmp("Event", tag) == 0;
00347
00348 if (strcmp("Response", tag) == 0 || isEvent)
00349 {
00350
00351 while (*attr)
00352 {
00353 const char *key = *attr++;
00354 const char *value = *attr++;
00355
00356 if (strcmp("requestId", key) == 0)
00357 {
00358 uuidString = value;
00359 }
00360 else if (strcmp("action", key) == 0)
00361 {
00362 actionString = value;
00363 }
00364 else if (strcmp("type", key) == 0)
00365 {
00366 eventTypeString = value;
00367 }
00368 }
00369 }
00370
00371 }
00372 else
00373 {
00374 if (ignoringTags)
00375 {
00376
00377 }
00378 else
00379 {
00380
00381
00382
00383 if (strcmp("InputXml", tag) == 0)
00384 {
00385 ignoringTags = true;
00386 ignoreDepth = responseDepth;
00387 accumulateText = false;
00388
00389
00390 }
00391 else if (strcmp("CaptureDevices", tag) == 0)
00392 {
00393 gVoiceClient->clearCaptureDevices();
00394 }
00395 else if (strcmp("RenderDevices", tag) == 0)
00396 {
00397 gVoiceClient->clearRenderDevices();
00398 }
00399 }
00400 }
00401 responseDepth++;
00402 }
00403
00404
00405
00406 void LLVivoxProtocolParser::EndTag(const char *tag)
00407 {
00408 const char *string = textBuffer.c_str();
00409 bool clearbuffer = true;
00410
00411 responseDepth--;
00412
00413 if (ignoringTags)
00414 {
00415 if (ignoreDepth == responseDepth)
00416 {
00417
00418 ignoringTags = false;
00419 }
00420 else
00421 {
00422
00423 }
00424 }
00425
00426 if (!ignoringTags)
00427 {
00428
00429
00430
00431 if (strcmp("ReturnCode", tag) == 0)
00432 returnCode = strtol(string, NULL, 10);
00433 else if (strcmp("StatusCode", tag) == 0)
00434 statusCode = strtol(string, NULL, 10);
00435 else if (strcmp("ConnectorHandle", tag) == 0)
00436 connectorHandle = string;
00437 else if (strcmp("AccountHandle", tag) == 0)
00438 accountHandle = string;
00439 else if (strcmp("SessionHandle", tag) == 0)
00440 {
00441 if (isEvent)
00442 eventSessionHandle = string;
00443 else
00444 sessionHandle = string;
00445 }
00446 else if (strcmp("StatusString", tag) == 0)
00447 statusString = string;
00448 else if (strcmp("State", tag) == 0)
00449 state = strtol(string, NULL, 10);
00450 else if (strcmp("URI", tag) == 0)
00451 uriString = string;
00452 else if (strcmp("IsChannel", tag) == 0)
00453 isChannel = strcmp(string, "true") == 0;
00454 else if (strcmp("Name", tag) == 0)
00455 nameString = string;
00456 else if (strcmp("AudioMedia", tag) == 0)
00457 audioMediaString = string;
00458 else if (strcmp("ChannelName", tag) == 0)
00459 nameString = string;
00460 else if (strcmp("ParticipantURI", tag) == 0)
00461 uriString = string;
00462 else if (strcmp("DisplayName", tag) == 0)
00463 displayNameString = string;
00464 else if (strcmp("AccountName", tag) == 0)
00465 nameString = string;
00466 else if (strcmp("ParticipantTyppe", tag) == 0)
00467 participantType = strtol(string, NULL, 10);
00468 else if (strcmp("IsLocallyMuted", tag) == 0)
00469 isLocallyMuted = strcmp(string, "true") == 0;
00470 else if (strcmp("IsModeratorMuted", tag) == 0)
00471 isModeratorMuted = strcmp(string, "true") == 0;
00472 else if (strcmp("IsSpeaking", tag) == 0)
00473 isSpeaking = strcmp(string, "true") == 0;
00474 else if (strcmp("Volume", tag) == 0)
00475 volume = strtol(string, NULL, 10);
00476 else if (strcmp("Energy", tag) == 0)
00477 energy = (F32)strtod(string, NULL);
00478 else if (strcmp("MicEnergy", tag) == 0)
00479 energy = (F32)strtod(string, NULL);
00480 else if (strcmp("ChannelName", tag) == 0)
00481 nameString = string;
00482 else if (strcmp("ChannelURI", tag) == 0)
00483 uriString = string;
00484 else if (strcmp("ChannelListResult", tag) == 0)
00485 {
00486 gVoiceClient->addChannelMapEntry(nameString, uriString);
00487 }
00488 else if (strcmp("Device", tag) == 0)
00489 {
00490
00491 clearbuffer = false;
00492 }
00493 else if (strcmp("CaptureDevice", tag) == 0)
00494 {
00495 gVoiceClient->addCaptureDevice(textBuffer);
00496 }
00497 else if (strcmp("RenderDevice", tag) == 0)
00498 {
00499 gVoiceClient->addRenderDevice(textBuffer);
00500 }
00501
00502 if(clearbuffer)
00503 {
00504 textBuffer.clear();
00505 accumulateText= false;
00506 }
00507
00508 if (responseDepth == 0)
00509 {
00510
00511 processResponse(tag);
00512 }
00513 }
00514 }
00515
00516
00517
00518 void LLVivoxProtocolParser::CharData(const char *buffer, int length)
00519 {
00520
00521
00522
00523
00524
00525
00526
00527 if (accumulateText)
00528 textBuffer.append(buffer, length);
00529 }
00530
00531
00532
00533 void LLVivoxProtocolParser::processResponse(std::string tag)
00534 {
00535
00536
00537 if (isEvent)
00538 {
00539 if (eventTypeString == "LoginStateChangeEvent")
00540 {
00541 gVoiceClient->loginStateChangeEvent(accountHandle, statusCode, statusString, state);
00542 }
00543 else if (eventTypeString == "SessionNewEvent")
00544 {
00545 gVoiceClient->sessionNewEvent(accountHandle, eventSessionHandle, state, nameString, uriString);
00546 }
00547 else if (eventTypeString == "SessionStateChangeEvent")
00548 {
00549 gVoiceClient->sessionStateChangeEvent(uriString, statusCode, statusString, eventSessionHandle, state, isChannel, nameString);
00550 }
00551 else if (eventTypeString == "ParticipantStateChangeEvent")
00552 {
00553 gVoiceClient->participantStateChangeEvent(uriString, statusCode, statusString, state, nameString, displayNameString, participantType);
00554
00555 }
00556 else if (eventTypeString == "ParticipantPropertiesEvent")
00557 {
00558 gVoiceClient->participantPropertiesEvent(uriString, statusCode, statusString, isLocallyMuted, isModeratorMuted, isSpeaking, volume, energy);
00559 }
00560 else if (eventTypeString == "AuxAudioPropertiesEvent")
00561 {
00562 gVoiceClient->auxAudioPropertiesEvent(energy);
00563 }
00564 }
00565 else
00566 {
00567 if (actionString == "Connector.Create.1")
00568 {
00569 gVoiceClient->connectorCreateResponse(statusCode, statusString, connectorHandle);
00570 }
00571 else if (actionString == "Account.Login.1")
00572 {
00573 gVoiceClient->loginResponse(statusCode, statusString, accountHandle);
00574 }
00575 else if (actionString == "Session.Create.1")
00576 {
00577 gVoiceClient->sessionCreateResponse(statusCode, statusString, sessionHandle);
00578 }
00579 else if (actionString == "Session.Connect.1")
00580 {
00581 gVoiceClient->sessionConnectResponse(statusCode, statusString);
00582 }
00583 else if (actionString == "Session.Terminate.1")
00584 {
00585 gVoiceClient->sessionTerminateResponse(statusCode, statusString);
00586 }
00587 else if (actionString == "Account.Logout.1")
00588 {
00589 gVoiceClient->logoutResponse(statusCode, statusString);
00590 }
00591 else if (actionString == "Connector.InitiateShutdown.1")
00592 {
00593 gVoiceClient->connectorShutdownResponse(statusCode, statusString);
00594 }
00595 else if (actionString == "Account.ChannelGetList.1")
00596 {
00597 gVoiceClient->channelGetListResponse(statusCode, statusString);
00598 }
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 }
00678 }
00679
00681
00682 class LLVoiceClientPrefsListener: public LLSimpleListener
00683 {
00684 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
00685 {
00686
00687
00688 gVoiceClient->setVoiceEnabled(gSavedSettings.getBOOL("EnableVoiceChat"));
00689 gVoiceClient->setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
00690 std::string keyString = gSavedSettings.getString("PushToTalkButton");
00691 gVoiceClient->setPTTKey(keyString);
00692 gVoiceClient->setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
00693 gVoiceClient->setEarLocation(gSavedSettings.getS32("VoiceEarLocation"));
00694 std::string serverName = gSavedSettings.getString("VivoxDebugServerName");
00695 gVoiceClient->setVivoxDebugServerName(serverName);
00696
00697 std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
00698 gVoiceClient->setCaptureDevice(inputDevice);
00699 std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
00700 gVoiceClient->setRenderDevice(outputDevice);
00701
00702 return true;
00703 }
00704 };
00705 static LLVoiceClientPrefsListener voice_prefs_listener;
00706
00707 class LLVoiceClientMuteListObserver : public LLMuteListObserver
00708 {
00709 void onChange() { gVoiceClient->muteListChanged();}
00710 };
00711 static LLVoiceClientMuteListObserver mutelist_listener;
00712 static bool sMuteListListener_listening = false;
00713
00715
00716 class LLVoiceClientCapResponder : public LLHTTPClient::Responder
00717 {
00718 public:
00719 LLVoiceClientCapResponder(void){};
00720
00721 virtual void error(U32 status, const std::string& reason);
00722 virtual void result(const LLSD& content);
00723
00724 private:
00725 };
00726
00727 void LLVoiceClientCapResponder::error(U32 status, const std::string& reason)
00728 {
00729 llwarns << "LLVoiceClientCapResponder::error("
00730 << status << ": " << reason << ")"
00731 << llendl;
00732 }
00733
00734 void LLVoiceClientCapResponder::result(const LLSD& content)
00735 {
00736 LLSD::map_const_iterator iter;
00737 for(iter = content.beginMap(); iter != content.endMap(); ++iter)
00738 {
00739 llinfos << "LLVoiceClientCapResponder::result got "
00740 << iter->first << llendl;
00741 }
00742
00743 if ( content.has("voice_credentials") )
00744 {
00745 LLSD voice_credentials = content["voice_credentials"];
00746 std::string uri;
00747 std::string credentials;
00748
00749 if ( voice_credentials.has("channel_uri") )
00750 {
00751 uri = voice_credentials["channel_uri"].asString();
00752 }
00753 if ( voice_credentials.has("channel_credentials") )
00754 {
00755 credentials =
00756 voice_credentials["channel_credentials"].asString();
00757 }
00758
00759 gVoiceClient->setSpatialChannel(uri, credentials);
00760 }
00761 }
00762
00763
00764
00765 #if LL_WINDOWS
00766 static HANDLE sGatewayHandle = 0;
00767
00768 static bool isGatewayRunning()
00769 {
00770 bool result = false;
00771 if(sGatewayHandle != 0)
00772 {
00773 DWORD waitresult = WaitForSingleObject(sGatewayHandle, 0);
00774 if(waitresult != WAIT_OBJECT_0)
00775 {
00776 result = true;
00777 }
00778 }
00779 return result;
00780 }
00781 static void killGateway()
00782 {
00783 if(sGatewayHandle != 0)
00784 {
00785 TerminateProcess(sGatewayHandle,0);
00786 }
00787 }
00788
00789 #else // Mac and linux
00790
00791 static pid_t sGatewayPID = 0;
00792 static bool isGatewayRunning()
00793 {
00794 bool result = false;
00795 if(sGatewayPID != 0)
00796 {
00797
00798 if(kill(sGatewayPID, 0) == 0)
00799 {
00800 result = true;
00801 }
00802 }
00803 return result;
00804 }
00805
00806 static void killGateway()
00807 {
00808 if(sGatewayPID != 0)
00809 {
00810 kill(sGatewayPID, SIGTERM);
00811 }
00812 }
00813
00814 #endif
00815
00817
00818 LLVoiceClient::LLVoiceClient()
00819 {
00820 gVoiceClient = this;
00821 mWriteInProgress = false;
00822 mAreaVoiceDisabled = false;
00823 mPTT = true;
00824 mUserPTTState = false;
00825 mMuteMic = false;
00826 mSessionTerminateRequested = false;
00827 mCommandCookie = 0;
00828 mNonSpatialChannel = false;
00829 mNextSessionSpatial = true;
00830 mNextSessionNoReconnect = false;
00831 mSessionP2P = false;
00832 mCurrentParcelLocalID = 0;
00833 mLoginRetryCount = 0;
00834 mVivoxErrorStatusCode = 0;
00835
00836 mNextSessionResetOnClose = false;
00837 mSessionResetOnClose = false;
00838 mSpeakerVolume = 0;
00839 mMicVolume = 0;
00840
00841
00842 mSpatialCoordsDirty = false;
00843 mPTTDirty = true;
00844 mVolumeDirty = true;
00845 mSpeakerVolumeDirty = true;
00846 mMicVolumeDirty = true;
00847 mCaptureDeviceDirty = false;
00848 mRenderDeviceDirty = false;
00849
00850
00851 mVoiceEnabled = gSavedSettings.getBOOL("EnableVoiceChat");
00852 mUsePTT = gSavedSettings.getBOOL("EnablePushToTalk");
00853 std::string keyString = gSavedSettings.getString("PushToTalkButton");
00854 setPTTKey(keyString);
00855 mPTTIsToggle = gSavedSettings.getBOOL("PushToTalkToggle");
00856 mEarLocation = gSavedSettings.getS32("VoiceEarLocation");
00857 setVoiceVolume(gSavedSettings.getF32("AudioLevelVoice"));
00858 std::string captureDevice = gSavedSettings.getString("VoiceInputAudioDevice");
00859 setCaptureDevice(captureDevice);
00860 std::string renderDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
00861 setRenderDevice(renderDevice);
00862
00863
00864 gSavedSettings.getControl("EnableVoiceChat")->addListener(&voice_prefs_listener);
00865 gSavedSettings.getControl("PTTCurrentlyEnabled")->addListener(&voice_prefs_listener);
00866 gSavedSettings.getControl("PushToTalkButton")->addListener(&voice_prefs_listener);
00867 gSavedSettings.getControl("PushToTalkToggle")->addListener(&voice_prefs_listener);
00868 gSavedSettings.getControl("VoiceEarLocation")->addListener(&voice_prefs_listener);
00869 gSavedSettings.getControl("VivoxDebugServerName")->addListener(&voice_prefs_listener);
00870 gSavedSettings.getControl("VoiceInputAudioDevice")->addListener(&voice_prefs_listener);
00871 gSavedSettings.getControl("VoiceOutputAudioDevice")->addListener(&voice_prefs_listener);
00872
00873 mTuningMode = false;
00874 mTuningEnergy = 0.0f;
00875 mTuningMicVolume = 0;
00876 mTuningMicVolumeDirty = true;
00877 mTuningSpeakerVolume = 0;
00878 mTuningSpeakerVolumeDirty = true;
00879 mTuningCaptureRunning = false;
00880
00881
00882
00883
00884 mParticipantMapChanged = false;
00885
00886
00887
00888 mPump = NULL;
00889
00890 #if LL_DARWIN || LL_LINUX
00891
00892
00893
00894
00895 signal(SIGPIPE, SIG_IGN);
00896
00897
00898
00899 signal(SIGCHLD, SIG_IGN);
00900 #endif
00901
00902
00903 setState(stateDisabled);
00904
00905 gIdleCallbacks.addFunction(idle, this);
00906 }
00907
00908
00909
00910 LLVoiceClient::~LLVoiceClient()
00911 {
00912 }
00913
00914
00915
00916
00917
00918 void LLVoiceClient::init(LLPumpIO *pump)
00919 {
00920
00921 LLVoiceClient::getInstance()->mPump = pump;
00922 }
00923
00924 void LLVoiceClient::terminate()
00925 {
00926 if(gVoiceClient)
00927 {
00928 gVoiceClient->sessionTerminateSendMessage();
00929 gVoiceClient->logout();
00930 gVoiceClient->connectorShutdown();
00931 gVoiceClient->closeSocket();
00932
00933
00934
00935
00936
00937
00938
00939
00940 gVoiceClient = NULL;
00941 }
00942 }
00943
00944
00946
00947
00948 bool LLVoiceClient::writeString(const std::string &str)
00949 {
00950 bool result = false;
00951 if(mConnected)
00952 {
00953 apr_status_t err;
00954 apr_size_t size = (apr_size_t)str.size();
00955 apr_size_t written = size;
00956
00957
00958
00959
00960 err = apr_socket_send(
00961 mSocket->getSocket(),
00962 (const char*)str.data(),
00963 &written);
00964
00965 if(err == 0)
00966 {
00967
00968 result = true;
00969 }
00970
00971
00972
00973
00974
00975
00976 else
00977 {
00978
00979 char buf[MAX_STRING];
00980 llwarns << "apr error " << err << " ("<< apr_strerror(err, buf, MAX_STRING) << ") sending data to vivox daemon." << llendl;
00981 daemonDied();
00982 }
00983 }
00984
00985 return result;
00986 }
00987
00988
00990
00991 void LLVoiceClient::connectorCreate()
00992 {
00993 std::ostringstream stream;
00994 std::string logpath;
00995 std::string loglevel = "0";
00996
00997
00998 setState(stateConnectorStarting);
00999
01000 std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel");
01001
01002 if(savedLogLevel != "-1")
01003 {
01004 llinfos << "creating connector with logging enabled" << llendl;
01005 loglevel = "10";
01006 logpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
01007 }
01008
01009 stream
01010 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.Create.1\">"
01011 << "<ClientName>V2 SDK</ClientName>"
01012 << "<AccountManagementServer>" << mAccountServerURI << "</AccountManagementServer>"
01013 << "<Logging>"
01014 << "<Enabled>false</Enabled>"
01015 << "<Folder>" << logpath << "</Folder>"
01016 << "<FileNamePrefix>Connector</FileNamePrefix>"
01017 << "<FileNameSuffix>.log</FileNameSuffix>"
01018 << "<LogLevel>" << loglevel << "</LogLevel>"
01019 << "</Logging>"
01020 << "</Request>\n\n\n";
01021
01022 writeString(stream.str());
01023 }
01024
01025 void LLVoiceClient::connectorShutdown()
01026 {
01027 setState(stateConnectorStopping);
01028
01029 if(!mConnectorHandle.empty())
01030 {
01031 std::ostringstream stream;
01032 stream
01033 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.InitiateShutdown.1\">"
01034 << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
01035 << "</Request>"
01036 << "\n\n\n";
01037
01038 mConnectorHandle.clear();
01039
01040 writeString(stream.str());
01041 }
01042 }
01043
01044 void LLVoiceClient::userAuthorized(const std::string& firstName, const std::string& lastName, const LLUUID &agentID)
01045 {
01046 mAccountFirstName = firstName;
01047 mAccountLastName = lastName;
01048
01049 mAccountDisplayName = firstName;
01050 mAccountDisplayName += " ";
01051 mAccountDisplayName += lastName;
01052
01053 llinfos << "name \"" << mAccountDisplayName << "\" , ID " << agentID << llendl;
01054
01055 std::string userserver = gUserServerName;
01056 LLString::toLower(userserver);
01057 if((gUserServerChoice == USERSERVER_AGNI) ||
01058 ((gUserServerChoice == USERSERVER_OTHER) && (userserver.find("agni") != std::string::npos)))
01059 {
01060 sConnectingToAgni = true;
01061 }
01062
01063
01064 if(sConnectingToAgni)
01065 {
01066
01067 mAccountServerName = "bhr.vivox.com";
01068 mAccountServerURI = "https://www." + mAccountServerName + "/api2/";
01069 }
01070 else
01071 {
01072
01073 mAccountServerName = gSavedSettings.getString("VivoxDebugServerName");
01074 mAccountServerURI = "https://www." + mAccountServerName + "/api2/";
01075 }
01076
01077 mAccountName = nameFromID(agentID);
01078 }
01079
01080 void LLVoiceClient::requestVoiceAccountProvision(S32 retries)
01081 {
01082 if ( gAgent.getRegion() && mVoiceEnabled )
01083 {
01084 std::string url =
01085 gAgent.getRegion()->getCapability(
01086 "ProvisionVoiceAccountRequest");
01087
01088 if ( url == "" ) return;
01089
01090 LLHTTPClient::post(
01091 url,
01092 LLSD(),
01093 new LLViewerVoiceAccountProvisionResponder(retries));
01094 }
01095 }
01096
01097 void LLVoiceClient::login(
01098 const std::string& accountName,
01099 const std::string &password)
01100 {
01101 if((getState() >= stateLoggingIn) && (getState() < stateLoggedOut))
01102 {
01103
01104 llerrs << "called from wrong state." << llendl;
01105 }
01106 else if ( accountName != mAccountName )
01107 {
01108
01109 llinfos << "Wrong account name! " << accountName
01110 << " instead of " << mAccountName << llendl;
01111 }
01112 else
01113 {
01114 mAccountPassword = password;
01115 }
01116 }
01117
01118 void LLVoiceClient::idle(void* user_data)
01119 {
01120 LLVoiceClient* self = (LLVoiceClient*)user_data;
01121 self->stateMachine();
01122 }
01123
01124 const char *LLVoiceClient::state2string(LLVoiceClient::state inState)
01125 {
01126 const char *result = "UNKNOWN";
01127
01128
01129 #define CASE(x) case x: result = #x; break
01130
01131 switch(inState)
01132 {
01133 CASE(stateDisabled);
01134 CASE(stateStart);
01135 CASE(stateDaemonLaunched);
01136 CASE(stateConnecting);
01137 CASE(stateIdle);
01138 CASE(stateConnectorStart);
01139 CASE(stateConnectorStarting);
01140 CASE(stateConnectorStarted);
01141 CASE(stateMicTuningNoLogin);
01142 CASE(stateLoginRetry);
01143 CASE(stateLoginRetryWait);
01144 CASE(stateNeedsLogin);
01145 CASE(stateLoggingIn);
01146 CASE(stateLoggedIn);
01147 CASE(stateNoChannel);
01148 CASE(stateMicTuningLoggedIn);
01149 CASE(stateSessionCreate);
01150 CASE(stateSessionConnect);
01151 CASE(stateJoiningSession);
01152 CASE(stateSessionJoined);
01153 CASE(stateRunning);
01154 CASE(stateLeavingSession);
01155 CASE(stateSessionTerminated);
01156 CASE(stateLoggingOut);
01157 CASE(stateLoggedOut);
01158 CASE(stateConnectorStopping);
01159 CASE(stateConnectorStopped);
01160 CASE(stateConnectorFailed);
01161 CASE(stateConnectorFailedWaiting);
01162 CASE(stateLoginFailed);
01163 CASE(stateLoginFailedWaiting);
01164 CASE(stateJoinSessionFailed);
01165 CASE(stateJoinSessionFailedWaiting);
01166 CASE(stateJail);
01167 }
01168
01169 #undef CASE
01170
01171 return result;
01172 }
01173
01174 const char *LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus)
01175 {
01176 const char *result = "UNKNOWN";
01177
01178
01179 #define CASE(x) case x: result = #x; break
01180
01181 switch(inStatus)
01182 {
01183 CASE(STATUS_LOGIN_RETRY);
01184 CASE(STATUS_LOGGED_IN);
01185 CASE(STATUS_JOINING);
01186 CASE(STATUS_JOINED);
01187 CASE(STATUS_LEFT_CHANNEL);
01188 CASE(BEGIN_ERROR_STATUS);
01189 CASE(ERROR_CHANNEL_FULL);
01190 CASE(ERROR_CHANNEL_LOCKED);
01191 CASE(ERROR_NOT_AVAILABLE);
01192 CASE(ERROR_UNKNOWN);
01193 default:
01194 break;
01195 }
01196
01197 #undef CASE
01198
01199 return result;
01200 }
01201
01202 void LLVoiceClient::setState(state inState)
01203 {
01204 llinfos << "entering state " << state2string(inState) << llendl;
01205
01206 mState = inState;
01207 }
01208
01209 void LLVoiceClient::stateMachine()
01210 {
01211 if(gDisconnected)
01212 {
01213
01214 setVoiceEnabled(false);
01215 }
01216
01217 if(!mVoiceEnabled)
01218 {
01219 if(getState() != stateDisabled)
01220 {
01221
01222 if(!mConnected)
01223 {
01224
01225 llinfos << "Disabling voice before connection to daemon, terminating." << llendl;
01226 killGateway();
01227 }
01228
01229 sessionTerminateSendMessage();
01230 logout();
01231 connectorShutdown();
01232 closeSocket();
01233 removeAllParticipants();
01234
01235 setState(stateDisabled);
01236 }
01237 }
01238
01239
01240 {
01241 LLViewerRegion *region = gAgent.getRegion();
01242 LLParcel *parcel = NULL;
01243
01244 if(gParcelMgr)
01245 {
01246 parcel = gParcelMgr->getAgentParcel();
01247 }
01248
01249 if(region && parcel)
01250 {
01251 S32 parcelLocalID = parcel->getLocalID();
01252 std::string regionName = region->getName();
01253 std::string capURI = region->getCapability("ParcelVoiceInfoRequest");
01254
01255
01256
01257
01258
01259
01260 if(!regionName.empty() && !capURI.empty())
01261 {
01262 if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
01263 {
01264
01265 mCurrentParcelLocalID = parcelLocalID;
01266 mCurrentRegionName = regionName;
01267
01268 parcelChanged();
01269 }
01270 }
01271 }
01272 }
01273
01274 switch(getState())
01275 {
01276 case stateDisabled:
01277 if(mVoiceEnabled && (!mAccountName.empty() || mTuningMode))
01278 {
01279 setState(stateStart);
01280 }
01281 break;
01282
01283 case stateStart:
01284 if(gDisableVoice)
01285 {
01286
01287 setState(stateJail);
01288 }
01289 else if(!isGatewayRunning())
01290 {
01291 if(true)
01292 {
01293
01294 std::string exe_path = gDirUtilp->getAppRODataDir();
01295 exe_path += gDirUtilp->getDirDelimiter();
01296 #if LL_WINDOWS
01297 exe_path += "SLVoice.exe";
01298 #else
01299
01300 exe_path += "SLVoice";
01301 #endif
01302
01303 llstat s;
01304 if(!LLFile::stat(exe_path.c_str(), &s))
01305 {
01306
01307 std::string args = " -p tcp -h -c";
01308 std::string cmd;
01309 std::string loglevel = gSavedSettings.getString("VivoxDebugLevel");
01310
01311 if(loglevel.empty())
01312 {
01313 loglevel = "-1";
01314 }
01315
01316 args += " -ll ";
01317 args += loglevel;
01318
01319
01320
01321 #if LL_WINDOWS
01322 PROCESS_INFORMATION pinfo;
01323 STARTUPINFOA sinfo;
01324 memset(&sinfo, 0, sizeof(sinfo));
01325 std::string exe_dir = gDirUtilp->getAppRODataDir();
01326 cmd = "SLVoice.exe";
01327 cmd += args;
01328
01329
01330 char *args2 = new char[args.size() + 1];
01331 strcpy(args2, args.c_str());
01332
01333 if(!CreateProcessA(exe_path.c_str(), args2, NULL, NULL, FALSE, 0, NULL, exe_dir.c_str(), &sinfo, &pinfo))
01334 {
01335
01336 }
01337 else
01338 {
01339
01340
01341 sGatewayHandle = pinfo.hProcess;
01342 CloseHandle(pinfo.hThread);
01343 }
01344
01345 delete[] args2;
01346 #else // LL_WINDOWS
01347
01348 {
01349 std::vector<std::string> arglist;
01350 arglist.push_back(exe_path.c_str());
01351
01352
01353 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
01354 boost::char_separator<char> sep(" ");
01355 tokenizer tokens(args, sep);
01356 tokenizer::iterator token_iter;
01357
01358 for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
01359 {
01360 arglist.push_back(*token_iter);
01361 }
01362
01363
01364 char **fakeargv = new char*[arglist.size() + 1];
01365 int i;
01366 for(i=0; i < arglist.size(); i++)
01367 fakeargv[i] = const_cast<char*>(arglist[i].c_str());
01368
01369 fakeargv[i] = NULL;
01370
01371 pid_t id = vfork();
01372 if(id == 0)
01373 {
01374
01375 execv(exe_path.c_str(), fakeargv);
01376
01377
01378
01379 _exit(0);
01380 }
01381
01382
01383 delete[] fakeargv;
01384 sGatewayPID = id;
01385 }
01386 #endif // LL_WINDOWS
01387 mDaemonHost = LLHost(gSavedSettings.getString("VoiceHost").c_str(), gSavedSettings.getU32("VoicePort"));
01388 }
01389 else
01390 {
01391 llinfos << exe_path << "not found." << llendl
01392 }
01393 }
01394 else
01395 {
01396
01397
01398
01399
01400 mDaemonHost = LLHost(gSavedSettings.getString("VoiceHost").c_str(), gSavedSettings.getU32("VoicePort"));
01401 }
01402
01403 mUpdateTimer.start();
01404 mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS);
01405
01406 setState(stateDaemonLaunched);
01407
01408
01409 mPTTDirty = true;
01410 mSpeakerVolumeDirty = true;
01411
01412 mCaptureDeviceDirty = !mCaptureDevice.empty();
01413 mRenderDeviceDirty = !mRenderDevice.empty();
01414 }
01415 break;
01416
01417 case stateDaemonLaunched:
01418
01419 if(mUpdateTimer.hasExpired())
01420 {
01421 mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS);
01422
01423 if(!mSocket)
01424 {
01425 mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
01426 }
01427
01428 mConnected = mSocket->blockingConnect(mDaemonHost);
01429 if(mConnected)
01430 {
01431 setState(stateConnecting);
01432 }
01433 else
01434 {
01435
01436 closeSocket();
01437 }
01438 }
01439 break;
01440
01441 case stateConnecting:
01442
01443 if(mPump)
01444 {
01445
01446
01447
01448
01449
01450
01451 LLPumpIO::chain_t readChain;
01452
01453 readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket)));
01454 readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser()));
01455
01456 mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS);
01457
01458 setState(stateIdle);
01459 }
01460
01461 break;
01462
01463 case stateIdle:
01464
01465 getCaptureDevicesSendMessage();
01466 getRenderDevicesSendMessage();
01467
01468 mLoginRetryCount = 0;
01469
01470 setState(stateConnectorStart);
01471
01472 break;
01473
01474 case stateConnectorStart:
01475 if(!mVoiceEnabled)
01476 {
01477
01478 setState(stateLoggedOut);
01479 }
01480 else if(!mAccountServerURI.empty())
01481 {
01482 connectorCreate();
01483 }
01484 else if(mTuningMode)
01485 {
01486 setState(stateMicTuningNoLogin);
01487 }
01488 break;
01489
01490 case stateConnectorStarting:
01491
01492 break;
01493
01494 case stateConnectorStarted:
01495 if(!mVoiceEnabled)
01496 {
01497
01498 setState(stateLoggedOut);
01499 }
01500 else if(!mAccountName.empty())
01501 {
01502 LLViewerRegion *region = gAgent.getRegion();
01503
01504 if(region)
01505 {
01506 if ( region->getCapability("ProvisionVoiceAccountRequest") != "" )
01507 {
01508 if ( mAccountPassword.empty() )
01509 {
01510 requestVoiceAccountProvision();
01511 }
01512 setState(stateNeedsLogin);
01513 }
01514 }
01515 }
01516 break;
01517
01518 case stateMicTuningNoLogin:
01519 case stateMicTuningLoggedIn:
01520 {
01521
01522 if(mTuningMode && mVoiceEnabled && !mSessionTerminateRequested)
01523 {
01524 if(!mTuningCaptureRunning)
01525 {
01526
01527 tuningCaptureStartSendMessage(10000);
01528 }
01529
01530 if(mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty || mCaptureDeviceDirty || mRenderDeviceDirty)
01531 {
01532 std::ostringstream stream;
01533
01534 if(mTuningMicVolumeDirty)
01535 {
01536 stream
01537 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetMicLevel.1\">"
01538 << "<Level>" << mTuningMicVolume << "</Level>"
01539 << "</Request>\n\n\n";
01540 }
01541
01542 if(mTuningSpeakerVolumeDirty)
01543 {
01544 stream
01545 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetSpeakerLevel.1\">"
01546 << "<Level>" << mTuningSpeakerVolume << "</Level>"
01547 << "</Request>\n\n\n";
01548 }
01549
01550 if(mCaptureDeviceDirty)
01551 {
01552 buildSetCaptureDevice(stream);
01553 }
01554
01555 if(mRenderDeviceDirty)
01556 {
01557 buildSetRenderDevice(stream);
01558 }
01559
01560 mTuningMicVolumeDirty = false;
01561 mTuningSpeakerVolumeDirty = false;
01562 mCaptureDeviceDirty = false;
01563 mRenderDeviceDirty = false;
01564
01565 if(!stream.str().empty())
01566 {
01567 writeString(stream.str());
01568 }
01569 }
01570 }
01571 else
01572 {
01573
01574 if(mTuningCaptureRunning)
01575 {
01576 tuningCaptureStopSendMessage();
01577 }
01578
01579 if(getState() == stateMicTuningNoLogin)
01580 {
01581 setState(stateConnectorStart);
01582 }
01583 else
01584 {
01585 setState(stateNoChannel);
01586 }
01587 }
01588 }
01589 break;
01590
01591 case stateLoginRetry:
01592 if(mLoginRetryCount == 0)
01593 {
01594
01595 notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGIN_RETRY);
01596 }
01597
01598 mLoginRetryCount++;
01599
01600 if(mLoginRetryCount > MAX_LOGIN_RETRIES)
01601 {
01602 llinfos << "too many login retries, giving up." << llendl;
01603 setState(stateLoginFailed);
01604 }
01605 else
01606 {
01607 llinfos << "will retry login in " << LOGIN_RETRY_SECONDS << " seconds." << llendl;
01608 mUpdateTimer.start();
01609 mUpdateTimer.setTimerExpirySec(LOGIN_RETRY_SECONDS);
01610 setState(stateLoginRetryWait);
01611 }
01612 break;
01613
01614 case stateLoginRetryWait:
01615 if(mUpdateTimer.hasExpired())
01616 {
01617 setState(stateNeedsLogin);
01618 }
01619 break;
01620
01621 case stateNeedsLogin:
01622 if(!mAccountPassword.empty())
01623 {
01624 setState(stateLoggingIn);
01625 loginSendMessage();
01626 }
01627 break;
01628
01629 case stateLoggingIn:
01630
01631 break;
01632
01633 case stateLoggedIn:
01634
01635 parcelChanged();
01636
01637 notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
01638
01639
01640 if((!sMuteListListener_listening) && (gMuteListp))
01641 {
01642 gMuteListp->addObserver(&mutelist_listener);
01643 sMuteListListener_listening = true;
01644 }
01645
01646 setState(stateNoChannel);
01647 break;
01648
01649 case stateNoChannel:
01650 if(mSessionTerminateRequested || !mVoiceEnabled)
01651 {
01652
01653 setState(stateSessionTerminated);
01654 }
01655 else if(mTuningMode)
01656 {
01657 setState(stateMicTuningLoggedIn);
01658 }
01659 else if(!mNextSessionHandle.empty())
01660 {
01661 setState(stateSessionConnect);
01662 }
01663 else if(!mNextSessionURI.empty())
01664 {
01665 setState(stateSessionCreate);
01666 }
01667 break;
01668
01669 case stateSessionCreate:
01670 sessionCreateSendMessage();
01671 notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING);
01672 setState(stateJoiningSession);
01673 break;
01674
01675 case stateSessionConnect:
01676 sessionConnectSendMessage();
01677 notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING);
01678 setState(stateJoiningSession);
01679 break;
01680
01681 case stateJoiningSession:
01682
01683 if(!mVoiceEnabled)
01684 {
01685
01686 setState(stateSessionTerminated);
01687 }
01688 else if(mSessionTerminateRequested)
01689 {
01690 if(!mSessionHandle.empty())
01691 {
01692
01693
01694 if(mSessionP2P)
01695 {
01696 sessionTerminateSendMessage();
01697 setState(stateSessionTerminated);
01698 }
01699 }
01700 }
01701 break;
01702
01703 case stateSessionJoined:
01704
01705
01706
01707
01708 if(!mSessionHandle.empty())
01709 {
01710
01711
01712 notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED);
01713
01714
01715 mPTTDirty = true;
01716 mSpeakerVolumeDirty = true;
01717 mSpatialCoordsDirty = true;
01718
01719 setState(stateRunning);
01720
01721
01722 mUpdateTimer.start();
01723 mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
01724 }
01725 else if(!mVoiceEnabled)
01726 {
01727
01728 setState(stateSessionTerminated);
01729 }
01730 else if(mSessionTerminateRequested)
01731 {
01732
01733
01734 if(mSessionP2P)
01735 {
01736 sessionTerminateSendMessage();
01737 setState(stateSessionTerminated);
01738 }
01739 }
01740 break;
01741
01742 case stateRunning:
01743
01744
01745
01746 if(!mVoiceEnabled || mSessionTerminateRequested)
01747 {
01748 sessionTerminateSendMessage();
01749 }
01750 else
01751 {
01752
01753
01754 {
01755 bool newPTT;
01756 if(mUsePTT)
01757 {
01758
01759 newPTT = mUserPTTState;
01760 }
01761 else
01762 {
01763
01764 newPTT = true;
01765 }
01766
01767 if(mMuteMic)
01768 {
01769
01770 newPTT = false;
01771 }
01772
01773
01774 if(newPTT != mPTT)
01775 {
01776 mPTT = newPTT;
01777 mPTTDirty = true;
01778 }
01779 }
01780
01781 if(mNonSpatialChannel)
01782 {
01783
01784 mSpatialCoordsDirty = false;
01785 }
01786 else
01787 {
01788
01789 enforceTether();
01790 }
01791
01792
01793
01794 if(mVolumeDirty || mPTTDirty || mSpeakerVolumeDirty || mUpdateTimer.hasExpired())
01795 {
01796 mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
01797 sendPositionalUpdate();
01798 }
01799 }
01800 break;
01801
01802 case stateLeavingSession:
01803
01804 break;
01805
01806 case stateSessionTerminated:
01807
01808 mSessionTerminateRequested = false;
01809
01810 notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
01811
01812 if(mVoiceEnabled)
01813 {
01814
01815
01816 if(mNextSessionSpatial && mNextSessionURI.empty())
01817 {
01818 mNonSpatialChannel = !mNextSessionSpatial;
01819 }
01820
01821
01822 setState(stateNoChannel);
01823 }
01824 else
01825 {
01826
01827 logout();
01828 }
01829
01830 break;
01831
01832 case stateLoggingOut:
01833
01834 break;
01835 case stateLoggedOut:
01836
01837 connectorShutdown();
01838 break;
01839
01840 case stateConnectorStopping:
01841
01842 break;
01843
01844 case stateConnectorStopped:
01845
01846 closeSocket();
01847 removeAllParticipants();
01848 setState(stateDisabled);
01849 break;
01850
01851 case stateConnectorFailed:
01852 setState(stateConnectorFailedWaiting);
01853 break;
01854 case stateConnectorFailedWaiting:
01855 break;
01856
01857 case stateLoginFailed:
01858 setState(stateLoginFailedWaiting);
01859 break;
01860 case stateLoginFailedWaiting:
01861
01862 break;
01863
01864 case stateJoinSessionFailed:
01865
01866 llwarns << "stateJoinSessionFailed: (" << mVivoxErrorStatusCode << "): " << mVivoxErrorStatusString << llendl;
01867 notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
01868 setState(stateJoinSessionFailedWaiting);
01869 break;
01870
01871 case stateJoinSessionFailedWaiting:
01872
01873
01874 if(mSessionTerminateRequested)
01875 {
01876 setState(stateSessionTerminated);
01877 }
01878 break;
01879
01880 case stateJail:
01881
01882 break;
01883 }
01884
01885 if(mParticipantMapChanged)
01886 {
01887 mParticipantMapChanged = false;
01888 notifyObservers();
01889 }
01890
01891 }
01892
01893 void LLVoiceClient::closeSocket(void)
01894 {
01895 mSocket.reset();
01896 mConnected = false;
01897 }
01898
01899 void LLVoiceClient::loginSendMessage()
01900 {
01901 std::ostringstream stream;
01902 stream
01903 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Login.1\">"
01904 << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
01905 << "<AccountName>" << mAccountName << "</AccountName>"
01906 << "<AccountPassword>" << mAccountPassword << "</AccountPassword>"
01907 << "<AudioSessionAnswerMode>VerifyAnswer</AudioSessionAnswerMode>"
01908 << "</Request>\n\n\n";
01909
01910 writeString(stream.str());
01911 }
01912
01913 void LLVoiceClient::logout()
01914 {
01915 mAccountPassword = "";
01916 setState(stateLoggingOut);
01917 logoutSendMessage();
01918 }
01919
01920 void LLVoiceClient::logoutSendMessage()
01921 {
01922 if(!mAccountHandle.empty())
01923 {
01924 std::ostringstream stream;
01925 stream
01926 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.Logout.1\">"
01927 << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
01928 << "</Request>"
01929 << "\n\n\n";
01930
01931 mAccountHandle.clear();
01932
01933 writeString(stream.str());
01934 }
01935 }
01936
01937 void LLVoiceClient::channelGetListSendMessage()
01938 {
01939 std::ostringstream stream;
01940 stream
01941 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.ChannelGetList.1\">"
01942 << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
01943 << "</Request>\n\n\n";
01944
01945 writeString(stream.str());
01946 }
01947
01948 void LLVoiceClient::sessionCreateSendMessage()
01949 {
01950 llinfos << "requesting join: " << mNextSessionURI << llendl;
01951
01952 mSessionURI = mNextSessionURI;
01953 mNonSpatialChannel = !mNextSessionSpatial;
01954 mSessionResetOnClose = mNextSessionResetOnClose;
01955 mNextSessionResetOnClose = false;
01956 if(mNextSessionNoReconnect)
01957 {
01958
01959 mNextSessionURI.clear();
01960 }
01961
01962 mSessionP2P = mNextSessionNoReconnect;
01963
01964 std::ostringstream stream;
01965 stream
01966 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Create.1\">"
01967 << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
01968 << "<URI>" << mSessionURI << "</URI>";
01969
01970 static const std::string allowed_chars =
01971 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
01972 "0123456789"
01973 "-._~";
01974
01975 if(!mNextSessionHash.empty())
01976 {
01977 stream
01978 << "<Password>" << LLURI::escape(mNextSessionHash, allowed_chars) << "</Password>"
01979 << "<PasswordHashAlgorithm>SHA1UserName</PasswordHashAlgorithm>";
01980 }
01981
01982 stream
01983 << "<Name>" << mChannelName << "</Name>"
01984 << "</Request>\n\n\n";
01985 writeString(stream.str());
01986 }
01987
01988 void LLVoiceClient::sessionConnectSendMessage()
01989 {
01990 llinfos << "connecting to session handle: " << mNextSessionHandle << llendl;
01991
01992 mSessionHandle = mNextSessionHandle;
01993 mSessionURI = mNextP2PSessionURI;
01994 mNextSessionHandle.clear();
01995 mNextP2PSessionURI.clear();
01996 mNonSpatialChannel = !mNextSessionSpatial;
01997 mSessionResetOnClose = mNextSessionResetOnClose;
01998 mNextSessionResetOnClose = false;
01999
02000 mSessionP2P = true;
02001
02002 std::ostringstream stream;
02003
02004 stream
02005 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Connect.1\">"
02006 << "<SessionHandle>" << mSessionHandle << "</SessionHandle>"
02007 << "<AudioMedia>default</AudioMedia>"
02008 << "</Request>\n\n\n";
02009 writeString(stream.str());
02010 }
02011
02012 void LLVoiceClient::sessionTerminate()
02013 {
02014 mSessionTerminateRequested = true;
02015 }
02016
02017 void LLVoiceClient::sessionTerminateSendMessage()
02018 {
02019 llinfos << "leaving session: " << mSessionURI << llendl;
02020
02021 switch(getState())
02022 {
02023 case stateNoChannel:
02024
02025
02026 setState(stateJoinSessionFailedWaiting);
02027 break;
02028 case stateJoiningSession:
02029 case stateSessionJoined:
02030 case stateRunning:
02031 if(!mSessionHandle.empty())
02032 {
02033 sessionTerminateByHandle(mSessionHandle);
02034 setState(stateLeavingSession);
02035 }
02036 else
02037 {
02038 llwarns << "called with no session handle" << llendl;
02039 setState(stateSessionTerminated);
02040 }
02041 break;
02042 case stateJoinSessionFailed:
02043 case stateJoinSessionFailedWaiting:
02044 setState(stateSessionTerminated);
02045 break;
02046
02047 default:
02048 llwarns << "called from unknown state" << llendl;
02049 break;
02050 }
02051 }
02052
02053 void LLVoiceClient::sessionTerminateByHandle(std::string &sessionHandle)
02054 {
02055 llinfos << "Sending Session.Terminate with handle " << sessionHandle << llendl;
02056
02057 std::ostringstream stream;
02058 stream
02059 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Terminate.1\">"
02060 << "<SessionHandle>" << sessionHandle << "</SessionHandle>"
02061 << "</Request>"
02062 << "\n\n\n";
02063
02064 writeString(stream.str());
02065 }
02066
02067 void LLVoiceClient::getCaptureDevicesSendMessage()
02068 {
02069 std::ostringstream stream;
02070 stream
02071 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetCaptureDevices.1\">"
02072 << "</Request>\n\n\n";
02073
02074 writeString(stream.str());
02075 }
02076
02077 void LLVoiceClient::getRenderDevicesSendMessage()
02078 {
02079 std::ostringstream stream;
02080 stream
02081 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.GetRenderDevices.1\">"
02082 << "</Request>\n\n\n";
02083
02084 writeString(stream.str());
02085 }
02086
02087 void LLVoiceClient::clearCaptureDevices()
02088 {
02089
02090 llinfos << "called" << llendl;
02091 mCaptureDevices.clear();
02092 }
02093
02094 void LLVoiceClient::addCaptureDevice(const std::string& name)
02095 {
02096
02097 llinfos << name << llendl;
02098
02099 mCaptureDevices.push_back(name);
02100 }
02101
02102 LLVoiceClient::deviceList *LLVoiceClient::getCaptureDevices()
02103 {
02104 return &mCaptureDevices;
02105 }
02106
02107 void LLVoiceClient::setCaptureDevice(const std::string& name)
02108 {
02109 if(name == "Default")
02110 {
02111 if(!mCaptureDevice.empty())
02112 {
02113 mCaptureDevice.clear();
02114 mCaptureDeviceDirty = true;
02115 }
02116 }
02117 else
02118 {
02119 if(mCaptureDevice != name)
02120 {
02121 mCaptureDevice = name;
02122 mCaptureDeviceDirty = true;
02123 }
02124 }
02125 }
02126
02127 void LLVoiceClient::clearRenderDevices()
02128 {
02129
02130 llinfos << "called" << llendl;
02131 mRenderDevices.clear();
02132 }
02133
02134 void LLVoiceClient::addRenderDevice(const std::string& name)
02135 {
02136
02137 llinfos << name << llendl;
02138 mRenderDevices.push_back(name);
02139 }
02140
02141 LLVoiceClient::deviceList *LLVoiceClient::getRenderDevices()
02142 {
02143 return &mRenderDevices;
02144 }
02145
02146 void LLVoiceClient::setRenderDevice(const std::string& name)
02147 {
02148 if(name == "Default")
02149 {
02150 if(!mRenderDevice.empty())
02151 {
02152 mRenderDevice.clear();
02153 mRenderDeviceDirty = true;
02154 }
02155 }
02156 else
02157 {
02158 if(mRenderDevice != name)
02159 {
02160 mRenderDevice = name;
02161 mRenderDeviceDirty = true;
02162 }
02163 }
02164
02165 }
02166
02167 void LLVoiceClient::tuningStart()
02168 {
02169 mTuningMode = true;
02170 if(getState() >= stateNoChannel)
02171 {
02172 sessionTerminate();
02173 }
02174 }
02175
02176 void LLVoiceClient::tuningStop()
02177 {
02178 mTuningMode = false;
02179 }
02180
02181 bool LLVoiceClient::inTuningMode()
02182 {
02183 bool result = false;
02184 switch(getState())
02185 {
02186 case stateMicTuningNoLogin:
02187 case stateMicTuningLoggedIn:
02188 result = true;
02189 default:
02190 break;
02191 }
02192 return result;
02193 }
02194
02195 void LLVoiceClient::tuningRenderStartSendMessage(const std::string& name, bool loop)
02196 {
02197 if(!inTuningMode())
02198 return;
02199
02200 mTuningAudioFile = name;
02201 std::ostringstream stream;
02202 stream
02203 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStart.1\">"
02204 << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
02205 << "<Loop>" << (loop?"1":"0") << "</Loop>"
02206 << "</Request>\n\n\n";
02207
02208 writeString(stream.str());
02209 }
02210
02211 void LLVoiceClient::tuningRenderStopSendMessage()
02212 {
02213 if(!inTuningMode())
02214 return;
02215
02216 std::ostringstream stream;
02217 stream
02218 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.RenderAudioStop.1\">"
02219 << "<SoundFilePath>" << mTuningAudioFile << "</SoundFilePath>"
02220 << "</Request>\n\n\n";
02221
02222 writeString(stream.str());
02223 }
02224
02225 void LLVoiceClient::tuningCaptureStartSendMessage(int duration)
02226 {
02227 if(!inTuningMode())
02228 return;
02229
02230 std::ostringstream stream;
02231 stream
02232 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStart.1\">"
02233 << "<Duration>" << duration << "</Duration>"
02234 << "</Request>\n\n\n";
02235
02236 writeString(stream.str());
02237
02238 mTuningCaptureRunning = true;
02239 }
02240
02241 void LLVoiceClient::tuningCaptureStopSendMessage()
02242 {
02243 if(!inTuningMode())
02244 return;
02245
02246 std::ostringstream stream;
02247 stream
02248 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.CaptureAudioStop.1\">"
02249 << "</Request>\n\n\n";
02250
02251 writeString(stream.str());
02252
02253 mTuningCaptureRunning = false;
02254 }
02255
02256 void LLVoiceClient::tuningSetMicVolume(float volume)
02257 {
02258 int scaledVolume = ((int)(volume * 100.0f)) - 100;
02259 if(scaledVolume != mTuningMicVolume)
02260 {
02261 mTuningMicVolume = scaledVolume;
02262 mTuningMicVolumeDirty = true;
02263 }
02264 }
02265
02266 void LLVoiceClient::tuningSetSpeakerVolume(float volume)
02267 {
02268 int scaledVolume = ((int)(volume * 100.0f)) - 100;
02269 if(scaledVolume != mTuningSpeakerVolume)
02270 {
02271 mTuningSpeakerVolume = ((int)(volume * 100.0f)) - 100;
02272 mTuningSpeakerVolumeDirty = true;
02273 }
02274 }
02275
02276 float LLVoiceClient::tuningGetEnergy(void)
02277 {
02278 return mTuningEnergy;
02279 }
02280
02281 bool LLVoiceClient::deviceSettingsAvailable()
02282 {
02283 bool result = true;
02284
02285 if(!mConnected)
02286 result = false;
02287
02288 if(mRenderDevices.empty())
02289 result = false;
02290
02291 return result;
02292 }
02293
02294 void LLVoiceClient::refreshDeviceLists(bool clearCurrentList)
02295 {
02296 if(clearCurrentList)
02297 {
02298 clearCaptureDevices();
02299 clearRenderDevices();
02300 }
02301 getCaptureDevicesSendMessage();
02302 getRenderDevicesSendMessage();
02303 }
02304
02305 void LLVoiceClient::daemonDied()
02306 {
02307
02308 llwarns << "Connection to vivox daemon lost. Resetting state."<< llendl;
02309
02310 closeSocket();
02311 removeAllParticipants();
02312
02313
02314 setState(stateDisabled);
02315 }
02316
02317 void LLVoiceClient::giveUp()
02318 {
02319
02320 closeSocket();
02321 removeAllParticipants();
02322
02323 setState(stateJail);
02324 }
02325
02326 void LLVoiceClient::sendPositionalUpdate(void)
02327 {
02328 std::ostringstream stream;
02329
02330 if(mSpatialCoordsDirty)
02331 {
02332 LLVector3 l, u, a;
02333
02334
02335 stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.Set3DPosition.1\">"
02336 << "<SessionHandle>" << mSessionHandle << "</SessionHandle>";
02337
02338 stream << "<SpeakerPosition>";
02339
02340 l = mAvatarRot.getLeftRow();
02341 u = mAvatarRot.getUpRow();
02342 a = mAvatarRot.getFwdRow();
02343
02344
02345
02346 stream
02347 << "<Position>"
02348 << "<X>" << mAvatarPosition[VX] << "</X>"
02349 << "<Y>" << mAvatarPosition[VZ] << "</Y>"
02350 << "<Z>" << mAvatarPosition[VY] << "</Z>"
02351 << "</Position>"
02352 << "<Velocity>"
02353 << "<X>" << mAvatarVelocity[VX] << "</X>"
02354 << "<Y>" << mAvatarVelocity[VZ] << "</Y>"
02355 << "<Z>" << mAvatarVelocity[VY] << "</Z>"
02356 << "</Velocity>"
02357 << "<AtOrientation>"
02358 << "<X>" << l.mV[VX] << "</X>"
02359 << "<Y>" << u.mV[VX] << "</Y>"
02360 << "<Z>" << a.mV[VX] << "</Z>"
02361 << "</AtOrientation>"
02362 << "<UpOrientation>"
02363 << "<X>" << l.mV[VZ] << "</X>"
02364 << "<Y>" << u.mV[VY] << "</Y>"
02365 << "<Z>" << a.mV[VZ] << "</Z>"
02366 << "</UpOrientation>"
02367 << "<LeftOrientation>"
02368 << "<X>" << l.mV [VY] << "</X>"
02369 << "<Y>" << u.mV [VZ] << "</Y>"
02370 << "<Z>" << a.mV [VY] << "</Z>"
02371 << "</LeftOrientation>";
02372
02373 stream << "</SpeakerPosition>";
02374
02375 stream << "<ListenerPosition>";
02376
02377 LLVector3d earPosition;
02378 LLVector3 earVelocity;
02379 LLMatrix3 earRot;
02380
02381 switch(mEarLocation)
02382 {
02383 case earLocCamera:
02384 default:
02385 earPosition = mCameraPosition;
02386 earVelocity = mCameraVelocity;
02387 earRot = mCameraRot;
02388 break;
02389
02390 case earLocAvatar:
02391 earPosition = mAvatarPosition;
02392 earVelocity = mAvatarVelocity;
02393 earRot = mAvatarRot;
02394 break;
02395
02396 case earLocMixed:
02397 earPosition = mAvatarPosition;
02398 earVelocity = mAvatarVelocity;
02399 earRot = mCameraRot;
02400 break;
02401 }
02402
02403 l = earRot.getLeftRow();
02404 u = earRot.getUpRow();
02405 a = earRot.getFwdRow();
02406
02407
02408
02409 stream
02410 << "<Position>"
02411 << "<X>" << earPosition[VX] << "</X>"
02412 << "<Y>" << earPosition[VZ] << "</Y>"
02413 << "<Z>" << earPosition[VY] << "</Z>"
02414 << "</Position>"
02415 << "<Velocity>"
02416 << "<X>" << earVelocity[VX] << "</X>"
02417 << "<Y>" << earVelocity[VZ] << "</Y>"
02418 << "<Z>" << earVelocity[VY] << "</Z>"
02419 << "</Velocity>"
02420 << "<AtOrientation>"
02421 << "<X>" << l.mV[VX] << "</X>"
02422 << "<Y>" << u.mV[VX] << "</Y>"
02423 << "<Z>" << a.mV[VX] << "</Z>"
02424 << "</AtOrientation>"
02425 << "<UpOrientation>"
02426 << "<X>" << l.mV[VZ] << "</X>"
02427 << "<Y>" << u.mV[VY] << "</Y>"
02428 << "<Z>" << a.mV[VZ] << "</Z>"
02429 << "</UpOrientation>"
02430 << "<LeftOrientation>"
02431 << "<X>" << l.mV [VY] << "</X>"
02432 << "<Y>" << u.mV [VZ] << "</Y>"
02433 << "<Z>" << a.mV [VY] << "</Z>"
02434 << "</LeftOrientation>";
02435
02436 stream << "</ListenerPosition>";
02437
02438 stream << "</Request>\n\n\n";
02439 }
02440
02441 if(mPTTDirty)
02442 {
02443
02444
02445
02446
02447
02448
02449 stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
02450 << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
02451 << "<Value>" << (mPTT?"false":"true") << "</Value>"
02452 << "</Request>\n\n\n";
02453
02454 }
02455
02456 if(mVolumeDirty)
02457 {
02458 participantMap::iterator iter = mParticipantMap.begin();
02459
02460 for(; iter != mParticipantMap.end(); iter++)
02461 {
02462 participantState *p = iter->second;
02463
02464 if(p->mVolumeDirty)
02465 {
02466 int volume = p->mOnMuteList?0:p->mUserVolume;
02467
02468 llinfos << "Setting volume for avatar " << p->mAvatarID << " to " << volume << llendl;
02469
02470
02471 stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Session.SetParticipantVolumeForMe.1\">"
02472 << "<SessionHandle>" << mSessionHandle << "</SessionHandle>"
02473 << "<ParticipantURI>" << p->mURI << "</ParticipantURI>"
02474 << "<Volume>" << volume << "</Volume>"
02475 << "</Request>\n\n\n";
02476
02477 p->mVolumeDirty = false;
02478 }
02479 }
02480 }
02481
02482 if(mSpeakerMuteDirty)
02483 {
02484 const char *muteval = ((mSpeakerVolume == -100)?"true":"false");
02485 llinfos << "Setting speaker mute to " << muteval << llendl;
02486
02487 stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalSpeaker.1\">"
02488 << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
02489 << "<Value>" << muteval << "</Value>"
02490 << "</Request>\n\n\n";
02491 }
02492
02493 if(mSpeakerVolumeDirty)
02494 {
02495 llinfos << "Setting speaker volume to " << mSpeakerVolume << llendl;
02496
02497 stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalSpeakerVolume.1\">"
02498 << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
02499 << "<Value>" << mSpeakerVolume << "</Value>"
02500 << "</Request>\n\n\n";
02501 }
02502
02503 if(mMicVolumeDirty)
02504 {
02505 llinfos << "Setting mic volume to " << mMicVolume << llendl;
02506
02507 stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.SetLocalMicVolume.1\">"
02508 << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
02509 << "<Value>" << mMicVolume << "</Value>"
02510 << "</Request>\n\n\n";
02511 }
02512
02513
02514
02515 if(mCaptureDeviceDirty)
02516 {
02517 buildSetCaptureDevice(stream);
02518 }
02519
02520 if(mRenderDeviceDirty)
02521 {
02522 buildSetRenderDevice(stream);
02523 }
02524
02525 mSpatialCoordsDirty = false;
02526 mPTTDirty = false;
02527 mVolumeDirty = false;
02528 mSpeakerVolumeDirty = false;
02529 mMicVolumeDirty = false;
02530 mSpeakerMuteDirty = false;
02531 mCaptureDeviceDirty = false;
02532 mRenderDeviceDirty = false;
02533
02534 if(!stream.str().empty())
02535 {
02536 writeString(stream.str());
02537 }
02538 }
02539
02540 void LLVoiceClient::buildSetCaptureDevice(std::ostringstream &stream)
02541 {
02542 llinfos << "Setting input device = \"" << mCaptureDevice << "\"" << llendl;
02543
02544 stream
02545 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetCaptureDevice.1\">"
02546 << "<CaptureDeviceSpecifier>" << mCaptureDevice << "</CaptureDeviceSpecifier>"
02547 << "</Request>"
02548 << "\n\n\n";
02549 }
02550
02551 void LLVoiceClient::buildSetRenderDevice(std::ostringstream &stream)
02552 {
02553 llinfos << "Setting output device = \"" << mRenderDevice << "\"" << llendl;
02554
02555 stream
02556 << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetRenderDevice.1\">"
02557 << "<RenderDeviceSpecifier>" << mRenderDevice << "</RenderDeviceSpecifier>"
02558 << "</Request>"
02559 << "\n\n\n";
02560 }
02561
02563
02564
02565 void LLVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle)
02566 {
02567 if(statusCode != 0)
02568 {
02569 llwarns << "Connector.Create response failure: " << statusString << llendl;
02570 setState(stateConnectorFailed);
02571 }
02572 else
02573 {
02574
02575 mConnectorHandle = connectorHandle;
02576 if(getState() == stateConnectorStarting)
02577 {
02578 setState(stateConnectorStarted);
02579 }
02580 }
02581 }
02582
02583 void LLVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle)
02584 {
02585 llinfos << "Account.Login response (" << statusCode << "): " << statusString << llendl;
02586
02587
02588
02589 if ( statusCode == 401 )
02590 {
02591
02592 llinfos << "Account.Login response failure (" << statusCode << "): " << statusString << llendl;
02593 setState(stateLoginRetry);
02594 }
02595 else if(statusCode != 0)
02596 {
02597 llwarns << "Account.Login response failure (" << statusCode << "): " << statusString << llendl;
02598 setState(stateLoginFailed);
02599 }
02600 else
02601 {
02602
02603 mAccountHandle = accountHandle;
02604
02605
02606
02607
02608
02609 }
02610 }
02611
02612 void LLVoiceClient::channelGetListResponse(int statusCode, std::string &statusString)
02613 {
02614 if(statusCode != 0)
02615 {
02616 llwarns << "Account.ChannelGetList response failure: " << statusString << llendl;
02617 switchChannel();
02618 }
02619 else
02620 {
02621
02622 std::string uri = findChannelURI(mChannelName);
02623 if(uri.empty())
02624 {
02625
02626 llinfos << "failed to map channel name: " << mChannelName << llendl;
02627 }
02628 else
02629 {
02630
02631 llinfos << "mapped channel " << mChannelName << " to URI "<< uri << llendl;
02632 }
02633
02634
02635 switchChannel(uri);
02636 }
02637 }
02638
02639 void LLVoiceClient::sessionCreateResponse(int statusCode, std::string &statusString, std::string &sessionHandle)
02640 {
02641 if(statusCode != 0)
02642 {
02643 llwarns << "Session.Create response failure (" << statusCode << "): " << statusString << llendl;
02644
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669
02670
02671
02672
02673
02674
02675 {
02676 mVivoxErrorStatusCode = statusCode;
02677 mVivoxErrorStatusString = statusString;
02678 setState(stateJoinSessionFailed);
02679 }
02680 }
02681 else
02682 {
02683 llinfos << "Session.Create response received (success), session handle is " << sessionHandle << llendl;
02684 if(getState() == stateJoiningSession)
02685 {
02686
02687 mSessionHandle = sessionHandle;
02688 }
02689 else
02690 {
02691
02692 sessionTerminateByHandle(sessionHandle);
02693 }
02694 }
02695 }
02696
02697 void LLVoiceClient::sessionConnectResponse(int statusCode, std::string &statusString)
02698 {
02699 if(statusCode != 0)
02700 {
02701 llwarns << "Session.Connect response failure (" << statusCode << "): " << statusString << llendl;
02702
02703
02704
02705
02706
02707
02708 {
02709 mVivoxErrorStatusCode = statusCode;
02710 mVivoxErrorStatusString = statusString;
02711 setState(stateJoinSessionFailed);
02712 }
02713 }
02714 else
02715 {
02716 llinfos << "Session.Connect response received (success)" << llendl;
02717 }
02718 }
02719
02720 void LLVoiceClient::sessionTerminateResponse(int statusCode, std::string &statusString)
02721 {
02722 if(statusCode != 0)
02723 {
02724 llwarns << "Session.Terminate response failure: (" << statusCode << "): " << statusString << llendl;
02725 if(getState() == stateLeavingSession)
02726 {
02727
02728
02729 setState(stateSessionTerminated);
02730 }
02731 }
02732
02733 }
02734
02735 void LLVoiceClient::logoutResponse(int statusCode, std::string &statusString)
02736 {
02737 if(statusCode != 0)
02738 {
02739 llwarns << "Account.Logout response failure: " << statusString << llendl;
02740
02741 }
02742
02743 if(getState() == stateLoggingOut)
02744 {
02745 setState(stateLoggedOut);
02746 }
02747 }
02748
02749 void LLVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString)
02750 {
02751 if(statusCode != 0)
02752 {
02753 llwarns << "Connector.InitiateShutdown response failure: " << statusString << llendl;
02754
02755 }
02756
02757 mConnected = false;
02758
02759 if(getState() == stateConnectorStopping)
02760 {
02761 setState(stateConnectorStopped);
02762 }
02763 }
02764
02765 void LLVoiceClient::sessionStateChangeEvent(
02766 std::string &uriString,
02767 int statusCode,
02768 std::string &statusString,
02769 std::string &sessionHandle,
02770 int state,
02771 bool isChannel,
02772 std::string &nameString)
02773 {
02774 switch(state)
02775 {
02776 case 4:
02777 llinfos << "joined session " << uriString << ", name " << nameString << " handle " << mNextSessionHandle << llendl;
02778
02779
02780 mSessionStateEventHandle = sessionHandle;
02781 mSessionStateEventURI = uriString;
02782 if(sessionHandle == mSessionHandle)
02783 {
02784
02785 if(getState() == stateJoiningSession)
02786 {
02787 setState(stateSessionJoined);
02788
02789
02790
02791
02792 }
02793 }
02794 else if(sessionHandle == mNextSessionHandle)
02795 {
02796
02797 }
02798 else
02799 {
02800 llwarns << "joining unknown session handle " << sessionHandle << ", URI " << uriString << ", name " << nameString << llendl;
02801
02802 }
02803
02804 break;
02805 case 5:
02806 llinfos << "left session " << uriString << ", name " << nameString << " handle " << mNextSessionHandle << llendl;
02807
02808
02809 if(sessionHandle == mSessionHandle)
02810 {
02811
02812
02813
02814 mSessionHandle.clear();
02815 if(mSessionResetOnClose)
02816 {
02817 mSessionResetOnClose = false;
02818 mNonSpatialChannel = false;
02819 mNextSessionSpatial = true;
02820 parcelChanged();
02821 }
02822
02823 removeAllParticipants();
02824
02825 switch(getState())
02826 {
02827 case stateJoiningSession:
02828 case stateSessionJoined:
02829 case stateRunning:
02830 case stateLeavingSession:
02831 case stateJoinSessionFailed:
02832 case stateJoinSessionFailedWaiting:
02833
02834 llinfos << "left session " << sessionHandle << "in state " << state2string(getState()) << llendl;
02835 setState(stateSessionTerminated);
02836 break;
02837
02838 case stateSessionTerminated:
02839
02840 llwarns << "left session " << sessionHandle << "in state " << state2string(getState()) << llendl;
02841 break;
02842
02843 default:
02844 llwarns << "unexpected SessionStateChangeEvent (left session) in state " << state2string(getState()) << llendl;
02845 setState(stateSessionTerminated);
02846 break;
02847 }
02848
02849
02850 mVivoxErrorStatusCode = statusCode;
02851 mVivoxErrorStatusString = statusString;
02852 }
02853 else
02854 {
02855 llinfos << "leaving unknown session handle " << sessionHandle << ", URI " << uriString << ", name " << nameString << llendl;
02856 }
02857
02858 mSessionStateEventHandle.clear();
02859 mSessionStateEventURI.clear();
02860 break;
02861 default:
02862 llwarns << "unknown state: " << state << llendl;
02863 break;
02864 }
02865 }
02866
02867 void LLVoiceClient::loginStateChangeEvent(
02868 std::string &accountHandle,
02869 int statusCode,
02870 std::string &statusString,
02871 int state)
02872 {
02873 llinfos << "state is " << state << llendl;
02874
02875
02876
02877
02878
02879
02880
02881
02882
02883
02884 switch(state)
02885 {
02886 case 1:
02887 if(getState() == stateLoggingIn)
02888 {
02889 setState(stateLoggedIn);
02890 }
02891 break;
02892
02893 default:
02894
02895 break;
02896 }
02897 }
02898
02899 void LLVoiceClient::sessionNewEvent(
02900 std::string &accountHandle,
02901 std::string &eventSessionHandle,
02902 int state,
02903 std::string &nameString,
02904 std::string &uriString)
02905 {
02906
02907
02908 switch(state)
02909 {
02910 case 0:
02911 {
02912 llinfos << "session handle = " << eventSessionHandle << ", name = " << nameString << ", uri = " << uriString << llendl;
02913
02914 LLUUID caller_id;
02915 if(IDFromName(nameString, caller_id))
02916 {
02917 gIMMgr->inviteToSession(LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, caller_id),
02918 LLString::null,
02919 caller_id,
02920 LLString::null,
02921 IM_SESSION_P2P_INVITE,
02922 eventSessionHandle);
02923 }
02924 else
02925 {
02926 llwarns << "Could not generate caller id from uri " << uriString << llendl;
02927 }
02928 }
02929 break;
02930
02931 default:
02932 llwarns << "unknown state: " << state << llendl;
02933 break;
02934 }
02935 }
02936
02937 void LLVoiceClient::participantStateChangeEvent(
02938 std::string &uriString,
02939 int statusCode,
02940 std::string &statusString,
02941 int state,
02942 std::string &nameString,
02943 std::string &displayNameString,
02944 int participantType)
02945 {
02946 participantState *participant = NULL;
02947 llinfos << "state is " << state << llendl;
02948
02949 switch(state)
02950 {
02951 case 7:
02952 participant = addParticipant(uriString);
02953 if(participant)
02954 {
02955 participant->mName = nameString;
02956 llinfos << "added participant \"" << participant->mName
02957 << "\" (" << participant->mAvatarID << ")"<< llendl;
02958 }
02959 break;
02960 case 9:
02961 participant = findParticipant(uriString);
02962 if(participant)
02963 {
02964 removeParticipant(participant);
02965 }
02966 break;
02967 default:
02968
02969 break;
02970 }
02971 }
02972
02973 void LLVoiceClient::participantPropertiesEvent(
02974 std::string &uriString,
02975 int statusCode,
02976 std::string &statusString,
02977 bool isLocallyMuted,
02978 bool isModeratorMuted,
02979 bool isSpeaking,
02980 int volume,
02981 F32 energy)
02982 {
02983 participantState *participant = findParticipant(uriString);
02984 if(participant)
02985 {
02986 participant->mPTT = !isLocallyMuted;
02987 participant->mIsSpeaking = isSpeaking;
02988 if (isSpeaking)
02989 {
02990 participant->mSpeakingTimeout.reset();
02991 }
02992 participant->mPower = energy;
02993 participant->mVolume = volume;
02994 }
02995 else
02996 {
02997 llwarns << "unknown participant: " << uriString << llendl;
02998 }
02999 }
03000
03001 void LLVoiceClient::auxAudioPropertiesEvent(F32 energy)
03002 {
03003
03004 mTuningEnergy = energy;
03005 }
03006
03007 void LLVoiceClient::muteListChanged()
03008 {
03009
03010
03011 participantMap::iterator iter = mParticipantMap.begin();
03012
03013 for(; iter != mParticipantMap.end(); iter++)
03014 {
03015 participantState *p = iter->second;
03016
03017
03018 updateMuteState(p);
03019 }
03020 }
03021
03023
03024 LLVoiceClient::participantState::participantState(const std::string &uri) :
03025 mURI(uri), mPTT(false), mIsSpeaking(false), mPower(0.0), mServiceType(serviceTypeUnknown),
03026 mOnMuteList(false), mUserVolume(100), mVolumeDirty(false), mAvatarIDValid(false)
03027 {
03028 }
03029
03030 LLVoiceClient::participantState *LLVoiceClient::addParticipant(const std::string &uri)
03031 {
03032 participantState *result = NULL;
03033
03034 participantMap::iterator iter = mParticipantMap.find(uri);
03035
03036 if(iter != mParticipantMap.end())
03037 {
03038
03039 result = iter->second;
03040 }
03041
03042 if(!result)
03043 {
03044
03045 result = new participantState(uri);
03046 mParticipantMap.insert(participantMap::value_type(uri, result));
03047 mParticipantMapChanged = true;
03048
03049
03050 {
03051 LLUUID id;
03052 if(IDFromName(uri, id))
03053 {
03054 result->mAvatarIDValid = true;
03055 result->mAvatarID = id;
03056
03057 updateMuteState(result);
03058 }
03059 }
03060
03061 llinfos << "participant \"" << result->mURI << "\" added." << llendl;
03062 }
03063
03064 return result;
03065 }
03066
03067 void LLVoiceClient::updateMuteState(participantState *p)
03068 {
03069 if(p->mAvatarIDValid)
03070 {
03071 bool isMuted = gMuteListp->isMuted(p->mAvatarID, LLMute::flagVoiceChat);
03072 if(p->mOnMuteList != isMuted)
03073 {
03074 p->mOnMuteList = isMuted;
03075 p->mVolumeDirty = true;
03076 mVolumeDirty = true;
03077 }
03078 }
03079 }
03080
03081 void LLVoiceClient::removeParticipant(LLVoiceClient::participantState *participant)
03082 {
03083 if(participant)
03084 {
03085 participantMap::iterator iter = mParticipantMap.find(participant->mURI);
03086
03087 llinfos << "participant \"" << participant->mURI << "\" (" << participant->mAvatarID << ") removed." << llendl;
03088
03089 mParticipantMap.erase(iter);
03090 delete participant;
03091 mParticipantMapChanged = true;
03092 }
03093 }
03094
03095 void LLVoiceClient::removeAllParticipants()
03096 {
03097 llinfos << "called" << llendl;
03098
03099 while(!mParticipantMap.empty())
03100 {
03101 removeParticipant(mParticipantMap.begin()->second);
03102 }
03103 }
03104
03105 LLVoiceClient::participantMap *LLVoiceClient::getParticipantList(void)
03106 {
03107 return &mParticipantMap;
03108 }
03109
03110
03111 LLVoiceClient::participantState *LLVoiceClient::findParticipant(const std::string &uri)
03112 {
03113 participantState *result = NULL;
03114
03115
03116
03117 if(mConnected)
03118 {
03119 participantMap::iterator iter = mParticipantMap.find(uri);
03120
03121 if(iter != mParticipantMap.end())
03122 {
03123 result = iter->second;
03124 }
03125 }
03126
03127 return result;
03128 }
03129
03130
03131 LLVoiceClient::participantState *LLVoiceClient::findParticipantByAvatar(LLVOAvatar *avatar)
03132 {
03133 participantState * result = NULL;
03134
03135
03136
03137
03138
03139 std::string loginName = nameFromAvatar(avatar);
03140 result = findParticipant(loginName);
03141
03142 if(result != NULL)
03143 {
03144 if(!result->mAvatarIDValid)
03145 {
03146 result->mAvatarID = avatar->getID();
03147 result->mAvatarIDValid = true;
03148
03149
03150 mParticipantMapChanged = true;
03151
03152 updateMuteState(result);
03153 }
03154
03155
03156 }
03157
03158 return result;
03159 }
03160
03161 LLVoiceClient::participantState* LLVoiceClient::findParticipantByID(const LLUUID& id)
03162 {
03163 participantState * result = NULL;
03164
03165
03166 std::string loginName = nameFromID(id);
03167 result = findParticipant(loginName);
03168
03169 return result;
03170 }
03171
03172
03173 void LLVoiceClient::clearChannelMap(void)
03174 {
03175 mChannelMap.clear();
03176 }
03177
03178 void LLVoiceClient::addChannelMapEntry(std::string &name, std::string &uri)
03179 {
03180
03181 mChannelMap.insert(channelMap::value_type(name, uri));
03182 }
03183
03184 std::string LLVoiceClient::findChannelURI(std::string &name)
03185 {
03186 std::string result;
03187
03188 channelMap::iterator iter = mChannelMap.find(name);
03189
03190 if(iter != mChannelMap.end())
03191 {
03192 result = iter->second;
03193 }
03194
03195 return result;
03196 }
03197
03198 void LLVoiceClient::parcelChanged()
03199 {
03200 if(getState() >= stateLoggedIn)
03201 {
03202
03203 llinfos << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << llendl;
03204
03205 std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
03206 LLSD data;
03207 data["method"] = "call";
03208 LLHTTPClient::post(
03209 url,
03210 data,
03211 new LLVoiceClientCapResponder);
03212 }
03213 else
03214 {
03215
03216 llinfos << "not logged in yet, deferring" << llendl;
03217 }
03218 }
03219
03220 void LLVoiceClient::switchChannel(
03221 std::string uri,
03222 bool spatial,
03223 bool noReconnect,
03224 std::string hash)
03225 {
03226 bool needsSwitch = false;
03227
03228 llinfos << "called in state " << state2string(getState()) << " with uri \"" << uri << "\"" << llendl;
03229
03230 switch(getState())
03231 {
03232 case stateJoinSessionFailed:
03233 case stateJoinSessionFailedWaiting:
03234 case stateNoChannel:
03235
03236 needsSwitch = true;
03237 break;
03238
03239 default:
03240 if(mSessionTerminateRequested)
03241 {
03242
03243 if(mNextSessionURI != uri)
03244 needsSwitch = true;
03245 }
03246 else
03247 {
03248
03249 if(mSessionURI != uri)
03250 needsSwitch = true;
03251 }
03252 break;
03253 }
03254
03255 if(needsSwitch)
03256 {
03257 mNextSessionURI = uri;
03258 mNextSessionHash = hash;
03259 mNextSessionHandle.clear();
03260 mNextP2PSessionURI.clear();
03261 mNextSessionSpatial = spatial;
03262 mNextSessionNoReconnect = noReconnect;
03263
03264 if(uri.empty())
03265 {
03266
03267 llinfos << "leaving channel" << llendl;
03268 }
03269 else
03270 {
03271 llinfos << "switching to channel " << uri << llendl;
03272 }
03273
03274 if(getState() <= stateNoChannel)
03275 {
03276
03277 }
03278 else
03279 {
03280
03281 sessionTerminate();
03282 }
03283 }
03284 }
03285
03286 void LLVoiceClient::joinSession(std::string handle, std::string uri)
03287 {
03288 mNextSessionURI.clear();
03289 mNextSessionHash.clear();
03290 mNextP2PSessionURI = uri;
03291 mNextSessionHandle = handle;
03292 mNextSessionSpatial = false;
03293 mNextSessionNoReconnect = false;
03294
03295 if(getState() <= stateNoChannel)
03296 {
03297
03298 }
03299 else
03300 {
03301
03302 sessionTerminate();
03303 }
03304 }
03305
03306 void LLVoiceClient::setNonSpatialChannel(
03307 const std::string &uri,
03308 const std::string &credentials)
03309 {
03310 switchChannel(uri, false, false, credentials);
03311 }
03312
03313 void LLVoiceClient::setSpatialChannel(
03314 const std::string &uri,
03315 const std::string &credentials)
03316 {
03317 mSpatialSessionURI = uri;
03318 mAreaVoiceDisabled = mSpatialSessionURI.empty();
03319
03320 llinfos << "got spatial channel uri: \"" << uri << "\"" << llendl;
03321
03322 if(mNonSpatialChannel || !mNextSessionSpatial)
03323 {
03324
03325 llinfos << "in non-spatial chat, not switching channels" << llendl;
03326 }
03327 else
03328 {
03329 switchChannel(mSpatialSessionURI, true, false, credentials);
03330 }
03331 }
03332
03333 void LLVoiceClient::callUser(LLUUID &uuid)
03334 {
03335 std::string userURI = sipURIFromID(uuid);
03336
03337 switchChannel(userURI, false, true);
03338 }
03339
03340 void LLVoiceClient::answerInvite(std::string &sessionHandle, LLUUID& other_user_id)
03341 {
03342 joinSession(sessionHandle, sipURIFromID(other_user_id));
03343 }
03344
03345 void LLVoiceClient::declineInvite(std::string &sessionHandle)
03346 {
03347 sessionTerminateByHandle(sessionHandle);
03348 }
03349
03350 void LLVoiceClient::leaveNonSpatialChannel()
03351 {
03352 switchChannel(mSpatialSessionURI);
03353 }
03354
03355 std::string LLVoiceClient::getCurrentChannel()
03356 {
03357 if((getState() == stateRunning) && !mSessionTerminateRequested)
03358 {
03359 return mSessionURI;
03360 }
03361
03362 return "";
03363 }
03364
03365 bool LLVoiceClient::inProximalChannel()
03366 {
03367 bool result = false;
03368
03369 if((getState() == stateRunning) && !mSessionTerminateRequested)
03370 {
03371 result = !mNonSpatialChannel;
03372 }
03373
03374 return result;
03375 }
03376
03377 std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
03378 {
03379 std::string result;
03380 result = "sip:";
03381 result += nameFromID(id);
03382 result += "@";
03383 result += mAccountServerName;
03384
03385 return result;
03386 }
03387
03388 std::string LLVoiceClient::sipURIFromAvatar(LLVOAvatar *avatar)
03389 {
03390 std::string result;
03391 if(avatar)
03392 {
03393 result = "sip:";
03394 result += nameFromID(avatar->getID());
03395 result += "@";
03396 result += mAccountServerName;
03397 }
03398
03399 return result;
03400 }
03401
03402 std::string LLVoiceClient::nameFromAvatar(LLVOAvatar *avatar)
03403 {
03404 std::string result;
03405 if(avatar)
03406 {
03407 result = nameFromID(avatar->getID());
03408 }
03409 return result;
03410 }
03411
03412 std::string LLVoiceClient::nameFromID(const LLUUID &uuid)
03413 {
03414 std::string result;
03415 U8 rawuuid[UUID_BYTES + 1];
03416 uuid.toCompressedString((char*)rawuuid);
03417
03418
03419 result = "x";
03420
03421
03422
03423
03424 result += LLBase64::encode(rawuuid, UUID_BYTES);
03425 LLString::replaceChar(result, '+', '-');
03426 LLString::replaceChar(result, '/', '_');
03427
03428
03429
03430
03431 return result;
03432 }
03433
03434 bool LLVoiceClient::IDFromName(const std::string name, LLUUID &uuid)
03435 {
03436 bool result = false;
03437
03438
03439
03440
03441
03442 if((name.size() == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '='))
03443 {
03444
03445
03446
03447 std::string temp = name;
03448 LLString::replaceChar(temp, '-', '+');
03449 LLString::replaceChar(temp, '_', '/');
03450
03451 U8 rawuuid[UUID_BYTES + 1];
03452 int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1);
03453 if(len == UUID_BYTES)
03454 {
03455
03456
03457
03458 memcpy(uuid.mData, rawuuid, UUID_BYTES);
03459 result = true;
03460 }
03461 }
03462
03463 return result;
03464 }
03465
03466 std::string LLVoiceClient::displayNameFromAvatar(LLVOAvatar *avatar)
03467 {
03468 return avatar->getFullname();
03469 }
03470
03471 std::string LLVoiceClient::sipURIFromName(std::string &name)
03472 {
03473 std::string result;
03474 result = "sip:";
03475 result += name;
03476 result += "@";
03477 result += mAccountServerName;
03478
03479
03480
03481 return result;
03482 }
03483
03485
03486
03487 void LLVoiceClient::enforceTether(void)
03488 {
03489 LLVector3d tethered = mCameraRequestedPosition;
03490
03491
03492 {
03493 F32 max_dist = 50.0f;
03494 LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition;
03495 F32 camera_distance = (F32)camera_offset.magVec();
03496 if(camera_distance > max_dist)
03497 {
03498 tethered = mAvatarPosition +
03499 (max_dist / camera_distance) * camera_offset;
03500 }
03501 }
03502
03503 if(dist_vec(mCameraPosition, tethered) > 0.1)
03504 {
03505 mCameraPosition = tethered;
03506 mSpatialCoordsDirty = true;
03507 }
03508 }
03509
03510 void LLVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
03511 {
03512 mCameraRequestedPosition = position;
03513
03514 if(mCameraVelocity != velocity)
03515 {
03516 mCameraVelocity = velocity;
03517 mSpatialCoordsDirty = true;
03518 }
03519
03520 if(mCameraRot != rot)
03521 {
03522 mCameraRot = rot;
03523 mSpatialCoordsDirty = true;
03524 }
03525 }
03526
03527 void LLVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
03528 {
03529 if(dist_vec(mAvatarPosition, position) > 0.1)
03530 {
03531 mAvatarPosition = position;
03532 mSpatialCoordsDirty = true;
03533 }
03534
03535 if(mAvatarVelocity != velocity)
03536 {
03537 mAvatarVelocity = velocity;
03538 mSpatialCoordsDirty = true;
03539 }
03540
03541 if(mAvatarRot != rot)
03542 {
03543 mAvatarRot = rot;
03544 mSpatialCoordsDirty = true;
03545 }
03546 }
03547
03548 bool LLVoiceClient::channelFromRegion(LLViewerRegion *region, std::string &name)
03549 {
03550 bool result = false;
03551
03552 if(region)
03553 {
03554 name = region->getName();
03555 }
03556
03557 if(!name.empty())
03558 result = true;
03559
03560 return result;
03561 }
03562
03563 void LLVoiceClient::leaveChannel(void)
03564 {
03565 if(getState() == stateRunning)
03566 {
03567
03568 mChannelName.clear();
03569 sessionTerminate();
03570 }
03571 }
03572
03573 void LLVoiceClient::setMuteMic(bool muted)
03574 {
03575 mMuteMic = muted;
03576 }
03577
03578 void LLVoiceClient::setUserPTTState(bool ptt)
03579 {
03580 mUserPTTState = ptt;
03581 }
03582
03583 bool LLVoiceClient::getUserPTTState()
03584 {
03585 return mUserPTTState;
03586 }
03587
03588 void LLVoiceClient::toggleUserPTTState(void)
03589 {
03590 mUserPTTState = !mUserPTTState;
03591 }
03592
03593 void LLVoiceClient::setVoiceEnabled(bool enabled)
03594 {
03595 if (enabled != mVoiceEnabled)
03596 {
03597 mVoiceEnabled = enabled;
03598 if (enabled)
03599 {
03600 LLVoiceChannel::getCurrentVoiceChannel()->activate();
03601 }
03602 else
03603 {
03604
03605
03606 }
03607 }
03608 }
03609
03610 bool LLVoiceClient::voiceEnabled()
03611 {
03612 return gSavedSettings.getBOOL("EnableVoiceChat") && !gDisableVoice;
03613 }
03614
03615 void LLVoiceClient::setUsePTT(bool usePTT)
03616 {
03617 if(usePTT && !mUsePTT)
03618 {
03619
03620 mUserPTTState = false;
03621 }
03622 mUsePTT = usePTT;
03623 }
03624
03625 void LLVoiceClient::setPTTIsToggle(bool PTTIsToggle)
03626 {
03627 if(!PTTIsToggle && mPTTIsToggle)
03628 {
03629
03630 mUserPTTState = false;
03631 }
03632
03633 mPTTIsToggle = PTTIsToggle;
03634 }
03635
03636
03637 void LLVoiceClient::setPTTKey(std::string &key)
03638 {
03639 if(key == "MiddleMouse")
03640 {
03641 mPTTIsMiddleMouse = true;
03642 }
03643 else
03644 {
03645 mPTTIsMiddleMouse = false;
03646 if(!LLKeyboard::keyFromString(key, &mPTTKey))
03647 {
03648
03649 key = KEY_NONE;
03650 }
03651 }
03652 }
03653
03654 void LLVoiceClient::setEarLocation(S32 loc)
03655 {
03656 if(mEarLocation != loc)
03657 {
03658 llinfos << "Setting mEarLocation to " << loc << llendl;
03659
03660 mEarLocation = loc;
03661 mSpatialCoordsDirty = true;
03662 }
03663 }
03664
03665 void LLVoiceClient::setVoiceVolume(F32 volume)
03666 {
03667 int scaledVolume = ((int)(volume * 100.0f)) - 100;
03668 if(scaledVolume != mSpeakerVolume)
03669 {
03670 if((scaledVolume == -100) || (mSpeakerVolume == -100))
03671 {
03672 mSpeakerMuteDirty = true;
03673 }
03674
03675 mSpeakerVolume = scaledVolume;
03676 mSpeakerVolumeDirty = true;
03677 }
03678 }
03679
03680 void LLVoiceClient::setMicGain(F32 volume)
03681 {
03682 int scaledVolume = ((int)(volume * 100.0f)) - 100;
03683 if(scaledVolume != mMicVolume)
03684 {
03685 mMicVolume = scaledVolume;
03686 mMicVolumeDirty = true;
03687 }
03688 }
03689
03690 void LLVoiceClient::setVivoxDebugServerName(std::string &serverName)
03691 {
03692 if(!mAccountServerName.empty())
03693 {
03694
03695 if(!sConnectingToAgni)
03696 {
03697
03698 mAccountServerName = serverName;
03699 }
03700 }
03701 }
03702
03703 void LLVoiceClient::keyDown(KEY key, MASK mask)
03704 {
03705
03706
03707 if (gKeyboard->getKeyRepeated(key))
03708 {
03709
03710 return;
03711 }
03712
03713 if(!mPTTIsMiddleMouse)
03714 {
03715 if(mPTTIsToggle)
03716 {
03717 if(key == mPTTKey)
03718 {
03719 toggleUserPTTState();
03720 }
03721 }
03722 else if(mPTTKey != KEY_NONE)
03723 {
03724 setUserPTTState(gKeyboard->getKeyDown(mPTTKey));
03725 }
03726 }
03727 }
03728 void LLVoiceClient::keyUp(KEY key, MASK mask)
03729 {
03730 if(!mPTTIsMiddleMouse)
03731 {
03732 if(!mPTTIsToggle && (mPTTKey != KEY_NONE))
03733 {
03734 setUserPTTState(gKeyboard->getKeyDown(mPTTKey));
03735 }
03736 }
03737 }
03738 void LLVoiceClient::middleMouseState(bool down)
03739 {
03740 if(mPTTIsMiddleMouse)
03741 {
03742 if(mPTTIsToggle)
03743 {
03744 if(down)
03745 {
03746 toggleUserPTTState();
03747 }
03748 }
03749 else
03750 {
03751 setUserPTTState(down);
03752 }
03753 }
03754 }
03755
03757
03758 BOOL LLVoiceClient::getVoiceEnabled(const LLUUID& id)
03759 {
03760 BOOL result = FALSE;
03761 participantState *participant = findParticipantByID(id);
03762 if(participant)
03763 {
03764
03765
03766 result = TRUE;
03767 }
03768
03769 return result;
03770 }
03771
03772 BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id)
03773 {
03774 BOOL result = FALSE;
03775
03776 participantState *participant = findParticipantByID(id);
03777 if(participant)
03778 {
03779 if (participant->mSpeakingTimeout.getElapsedTimeF32() > SPEAKING_TIMEOUT)
03780 {
03781 participant->mIsSpeaking = FALSE;
03782 }
03783 result = participant->mIsSpeaking;
03784 }
03785
03786 return result;
03787 }
03788
03789 F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
03790 {
03791 F32 result = 0;
03792 participantState *participant = findParticipantByID(id);
03793 if(participant)
03794 {
03795 result = participant->mPower;
03796 }
03797
03798 return result;
03799 }
03800
03801
03802 LLString LLVoiceClient::getDisplayName(const LLUUID& id)
03803 {
03804 LLString result;
03805 participantState *participant = findParticipantByID(id);
03806 if(participant)
03807 {
03808 result = participant->mDisplayName;
03809 }
03810
03811 return result;
03812 }
03813
03814
03815 BOOL LLVoiceClient::getUsingPTT(const LLUUID& id)
03816 {
03817 BOOL result = FALSE;
03818
03819 participantState *participant = findParticipantByID(id);
03820 if(participant)
03821 {
03822
03823
03824
03825 }
03826
03827 return result;
03828 }
03829
03830 BOOL LLVoiceClient::getPTTPressed(const LLUUID& id)
03831 {
03832 BOOL result = FALSE;
03833
03834 participantState *participant = findParticipantByID(id);
03835 if(participant)
03836 {
03837 result = participant->mPTT;
03838 }
03839
03840 return result;
03841 }
03842
03843 BOOL LLVoiceClient::getOnMuteList(const LLUUID& id)
03844 {
03845 BOOL result = FALSE;
03846
03847 participantState *participant = findParticipantByID(id);
03848 if(participant)
03849 {
03850 result = participant->mOnMuteList;
03851 }
03852
03853 return result;
03854 }
03855
03856
03857
03858 F32 LLVoiceClient::getUserVolume(const LLUUID& id)
03859 {
03860 F32 result = 0.0f;
03861
03862 participantState *participant = findParticipantByID(id);
03863 if(participant)
03864 {
03865 S32 ires = participant->mUserVolume;
03866 result = sqrtf(((F32)ires) / 400.f);
03867 }
03868
03869 return result;
03870 }
03871
03872 void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
03873 {
03874 participantState *participant = findParticipantByID(id);
03875 if (participant)
03876 {
03877
03878 S32 ivol = (S32)(400.f * volume * volume);
03879 participant->mUserVolume = llclamp(ivol, 0, 400);
03880 participant->mVolumeDirty = TRUE;
03881 mVolumeDirty = TRUE;
03882 }
03883 }
03884
03885
03886
03887 LLVoiceClient::serviceType LLVoiceClient::getServiceType(const LLUUID& id)
03888 {
03889 serviceType result = serviceTypeUnknown;
03890
03891 participantState *participant = findParticipantByID(id);
03892 if(participant)
03893 {
03894 result = participant->mServiceType;
03895 }
03896
03897 return result;
03898 }
03899
03900 std::string LLVoiceClient::getGroupID(const LLUUID& id)
03901 {
03902 std::string result;
03903
03904 participantState *participant = findParticipantByID(id);
03905 if(participant)
03906 {
03907 result = participant->mGroupID;
03908 }
03909
03910 return result;
03911 }
03912
03913 BOOL LLVoiceClient::getAreaVoiceDisabled()
03914 {
03915 return mAreaVoiceDisabled;
03916 }
03917
03918 void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
03919 {
03920 mObservers.insert(observer);
03921 }
03922
03923 void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
03924 {
03925 mObservers.erase(observer);
03926 }
03927
03928 void LLVoiceClient::notifyObservers()
03929 {
03930 for (observer_set_t::iterator it = mObservers.begin();
03931 it != mObservers.end();
03932 )
03933 {
03934 LLVoiceClientParticipantObserver* observer = *it;
03935 observer->onChange();
03936
03937 it = mObservers.upper_bound(observer);
03938 }
03939 }
03940
03941 void LLVoiceClient::addStatusObserver(LLVoiceClientStatusObserver* observer)
03942 {
03943 mStatusObservers.insert(observer);
03944 }
03945
03946 void LLVoiceClient::removeStatusObserver(LLVoiceClientStatusObserver* observer)
03947 {
03948 mStatusObservers.erase(observer);
03949 }
03950
03951 void LLVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status)
03952 {
03953 if(status == LLVoiceClientStatusObserver::ERROR_UNKNOWN)
03954 {
03955 switch(mVivoxErrorStatusCode)
03956 {
03957 case 20713: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_FULL; break;
03958 case 20714: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_LOCKED; break;
03959 case 20715: status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
03960 break;
03961 }
03962
03963
03964 mVivoxErrorStatusCode = 0;
03965 }
03966
03967 if (status == LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL
03968
03969 && (mVivoxErrorStatusCode == 404 || mVivoxErrorStatusCode == 480 || mVivoxErrorStatusCode == 408))
03970 {
03971
03972
03973 status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
03974
03975
03976 mVivoxErrorStatusCode = 0;
03977 }
03978
03979 llinfos << " " << LLVoiceClientStatusObserver::status2string(status) << ", session URI " << mSessionURI << llendl;
03980
03981 for (status_observer_set_t::iterator it = mStatusObservers.begin();
03982 it != mStatusObservers.end();
03983 )
03984 {
03985 LLVoiceClientStatusObserver* observer = *it;
03986 observer->onChange(status, mSessionURI, !mNonSpatialChannel);
03987
03988 it = mStatusObservers.upper_bound(observer);
03989 }
03990
03991 }
03992
03993
03994 void LLVoiceClient::onAvatarNameLookup(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* user_data)
03995 {
03996 participantState* statep = gVoiceClient->findParticipantByID(id);
03997
03998 if (statep)
03999 {
04000 statep->mDisplayName = llformat("%s %s", first, last);
04001 }
04002
04003 gVoiceClient->notifyObservers();
04004 }
04005
04006 class LLViewerParcelVoiceInfo : public LLHTTPNode
04007 {
04008 virtual void post(
04009 LLHTTPNode::ResponsePtr response,
04010 const LLSD& context,
04011 const LLSD& input) const
04012 {
04013
04014
04015
04016 if ( input.has("body") )
04017 {
04018 LLSD body = input["body"];
04019
04020
04021
04022
04023
04024
04025 if ( body.has("voice_credentials") )
04026 {
04027 LLSD voice_credentials = body["voice_credentials"];
04028 std::string uri;
04029 std::string credentials;
04030
04031 if ( voice_credentials.has("channel_uri") )
04032 {
04033 uri = voice_credentials["channel_uri"].asString();
04034 }
04035 if ( voice_credentials.has("channel_credentials") )
04036 {
04037 credentials =
04038 voice_credentials["channel_credentials"].asString();
04039 }
04040
04041 gVoiceClient->setSpatialChannel(uri, credentials);
04042 }
04043 }
04044 }
04045 };
04046
04047 class LLViewerRequiredVoiceVersion : public LLHTTPNode
04048 {
04049 static BOOL sAlertedUser;
04050 virtual void post(
04051 LLHTTPNode::ResponsePtr response,
04052 const LLSD& context,
04053 const LLSD& input) const
04054 {
04055
04056
04057 if ( input.has("body") && input["body"].has("major_version") )
04058 {
04059 int major_voice_version =
04060 input["body"]["major_version"].asInteger();
04061
04062
04063
04064 if (gVoiceClient &&
04065 (major_voice_version > VOICE_MAJOR_VERSION) )
04066 {
04067 if (!sAlertedUser)
04068 {
04069
04070 gViewerWindow->alertXml("VoiceVersionMismatch");
04071 gSavedSettings.setBOOL("EnableVoiceChat", FALSE);
04072 }
04073 }
04074 }
04075 }
04076 };
04077 BOOL LLViewerRequiredVoiceVersion::sAlertedUser = FALSE;
04078
04079 LLHTTPRegistration<LLViewerParcelVoiceInfo>
04080 gHTTPRegistrationMessageParcelVoiceInfo(
04081 "/message/ParcelVoiceInfo");
04082
04083 LLHTTPRegistration<LLViewerRequiredVoiceVersion>
04084 gHTTPRegistrationMessageRequiredVoiceVersion(
04085 "/message/RequiredVoiceVersion");