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