summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRider Linden <rider@lindenlab.com>2015-12-09 16:33:51 -0800
committerRider Linden <rider@lindenlab.com>2015-12-09 16:33:51 -0800
commit7e58b0793b021922e68e10f111d624bb7638fefa (patch)
tree82ae16d24920f1684b9d477ed351fe2f876c6ab7
parentaa67a2fba05a703364e91d034d4b9a2f5d2f26e2 (diff)
Voice session state now in coro (includes all sub states as part of the coro)
-rwxr-xr-xindra/newview/llvoiceclient.h2
-rwxr-xr-xindra/newview/llvoicevivox.cpp384
-rwxr-xr-xindra/newview/llvoicevivox.h15
3 files changed, 378 insertions, 23 deletions
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 51961468ca..b05bcb23b7 100755
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -156,7 +156,7 @@ public:
virtual void setNonSpatialChannel(const std::string &uri,
const std::string &credentials)=0;
- virtual void setSpatialChannel(const std::string &uri,
+ virtual bool setSpatialChannel(const std::string &uri,
const std::string &credentials)=0;
virtual void leaveNonSpatialChannel()=0;
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 7642fa55d8..867fc7ae68 100755
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -671,8 +671,10 @@ void LLVivoxVoiceClient::stateMachine()
if ((getState() == stateRunning) && inSpatialChannel() && mUpdateTimer.hasExpired() && !mTerminateDaemon)
{
+#if 0
// poll the avatar position so its available in various states when a 3d position is sent.
updatePosition();
+#endif
}
else if(mTuningMode)
{
@@ -1342,7 +1344,12 @@ void LLVivoxVoiceClient::stateMachine()
// state. If the cap request is still pending,
// the responder will check to see if we've moved
// to a new session and won't change any state.
+#if 1
+ LLCoros::instance().launch("LLVivoxVoiceClient::terminateAudioSession",
+ boost::bind(&LLVivoxVoiceClient::terminateAudioSession, this, true));
+#else
setState(stateSessionTerminated);
+#endif
}
break;
@@ -1355,8 +1362,13 @@ void LLVivoxVoiceClient::stateMachine()
if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized))
{
+#if 1
+ LLCoros::instance().launch("LLVivoxVoiceClient::terminateAudioSession",
+ boost::bind(&LLVivoxVoiceClient::terminateAudioSession, this, true));
+#else
// TODO: Question: Is this the right way out of this state?
setState(stateSessionTerminated);
+#endif
}
else if(mTuningMode)
{
@@ -1383,21 +1395,31 @@ void LLVivoxVoiceClient::stateMachine()
// the parcel is changed, or we have no pending audio sessions,
// so try to request the parcel voice info
// if we have the cap, we move to the appropriate state
+#if 1
+ LLCoros::instance().launch("LLVivoxVoiceClient::requestParcelVoiceInfo",
+ boost::bind(&LLVivoxVoiceClient::requestParcelVoiceInfo, this, stateNoChannel));
+#else
if(requestParcelVoiceInfo())
{
setState(stateRetrievingParcelVoiceInfo);
}
+#endif
}
else if(sessionNeedsRelog(mNextAudioSession))
{
requestRelog();
+#if 1
+ LLCoros::instance().launch("LLVivoxVoiceClient::terminateAudioSession",
+ boost::bind(&LLVivoxVoiceClient::terminateAudioSession, this, true));
+#else
setState(stateSessionTerminated);
+#endif
}
else if(mNextAudioSession)
{
#if 1
- LLCoros::instance().launch("LLVivoxVoiceClient::addAndJoinSession",
- boost::bind(&LLVivoxVoiceClient::addAndJoinSession, this, mNextAudioSession));
+ LLCoros::instance().launch("LLVivoxVoiceClient::runSession",
+ boost::bind(&LLVivoxVoiceClient::runSession, this, mNextAudioSession));
#else
// moved to addAndJoinSession()
sessionState *oldSession = mAudioSession;
@@ -1526,12 +1548,24 @@ void LLVivoxVoiceClient::stateMachine()
//-------------------------------------------------------------------------
#endif
- //MARK: stateRunning
- case stateRunning: // steady state
- // Disabling voice or disconnect requested.
+#if 1
+ //MARK: stateRunning
+ case stateRunning: // steady state
+ //MARK: stateRunning
+ // moved to runSession
+ break;
+#else
+ case stateRunning: // steady state
+ // Disabling voice or disconnect requested.
if((!mVoiceEnabled && mIsInitialized) || mSessionTerminateRequested)
{
+#if 1
+ mSessionTerminateRequested = false;
+ LLCoros::instance().launch("LLVivoxVoiceClient::terminateAudioSession",
+ boost::bind(&LLVivoxVoiceClient::terminateAudioSession, this, true));
+#else
leaveAudioSession();
+#endif
}
else
{
@@ -1549,12 +1583,17 @@ void LLVivoxVoiceClient::stateMachine()
// cap for the parcel voice info. If we can't request it
// then we don't have the cap URL so we do nothing and will
// recheck next time around
+#if 1
+ LLCoros::instance().launch("LLVivoxVoiceClient::requestParcelVoiceInfo",
+ boost::bind(&LLVivoxVoiceClient::requestParcelVoiceInfo, this, stateRunning));
+#else
if(requestParcelVoiceInfo())
{
// we did get the cap, and we made the request,
// so go wait for the response.
setState(stateRetrievingParcelVoiceInfo);
}
+#endif
}
// Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position)
enforceTether();
@@ -1579,7 +1618,14 @@ void LLVivoxVoiceClient::stateMachine()
mIsInitialized = true;
}
break;
-
+#endif
+
+#if 1
+ case stateLeavingSession: // waiting for terminate session response
+ case stateSessionTerminated:
+ // moved to terminateAudioSession
+ break;
+#else
//MARK: stateLeavingSession
case stateLeavingSession: // waiting for terminate session response
// The handler for the Session.Terminate response will transition from here to stateSessionTerminated.
@@ -1629,7 +1675,8 @@ void LLVivoxVoiceClient::stateMachine()
}
break;
-
+#endif
+
//MARK: stateLoggingOut
case stateLoggingOut: // waiting for logout response
// The handler for the AccountLoginStateChangeEvent will transition from here to stateLoggedOut.
@@ -1714,7 +1761,12 @@ void LLVivoxVoiceClient::stateMachine()
// Region crossings may leave this state and try the join again.
if(mSessionTerminateRequested)
{
+#if 1
+ LLCoros::instance().launch("LLVivoxVoiceClient::terminateAudioSession",
+ boost::bind(&LLVivoxVoiceClient::terminateAudioSession, this, true));
+#else
setState(stateSessionTerminated);
+#endif
}
break;
@@ -2185,6 +2237,79 @@ bool LLVivoxVoiceClient::retrieveVoiceFonts()
}
+bool LLVivoxVoiceClient::requestParcelVoiceInfo(state exitState)
+{
+ setState(stateRetrievingParcelVoiceInfo);
+
+ LLViewerRegion * region = gAgent.getRegion();
+ if (region == NULL || !region->capabilitiesReceived())
+ {
+ LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest capability not yet available, deferring" << LL_ENDL;
+ return false;
+ }
+
+ // grab the cap.
+ std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
+ if (url.empty())
+ {
+ // Region dosn't have the cap. Stop probing.
+ LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest capability not available in this region" << LL_ENDL;
+ setState(stateDisableCleanup);
+ return false;
+ }
+
+ // update the parcel
+ checkParcelChanged(true);
+
+ LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
+
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("parcelVoiceInfoRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD());
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("Voice") << "No voice on parcel" << LL_ENDL;
+ sessionTerminate();
+ return false;
+ }
+
+ std::string uri;
+ std::string credentials;
+
+ if (result.has("voice_credentials"))
+ {
+ LLSD voice_credentials = result["voice_credentials"];
+ if (voice_credentials.has("channel_uri"))
+ {
+ uri = voice_credentials["channel_uri"].asString();
+ }
+ if (voice_credentials.has("channel_credentials"))
+ {
+ credentials =
+ voice_credentials["channel_credentials"].asString();
+ }
+ }
+
+ if (!uri.empty())
+ LL_INFOS("Voice") << "Voice URI is " << uri << LL_ENDL;
+
+ // set the spatial channel. If no voice credentials or uri are
+ // available, then we simply drop out of voice spatially.
+ if (parcelVoiceInfoReceived(exitState))
+ {
+ return !setSpatialChannel(uri, credentials);
+ }
+
+ return false;
+}
+
bool LLVivoxVoiceClient::addAndJoinSession(sessionState *nextSession)
{
LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump");
@@ -2239,7 +2364,7 @@ bool LLVivoxVoiceClient::addAndJoinSession(sessionState *nextSession)
if (!mVoiceEnabled && mIsInitialized)
{
// User bailed out during connect -- jump straight to teardown.
- setState(stateSessionTerminated);
+ terminateAudioSession(true);
return false;
}
else if (mSessionTerminateRequested)
@@ -2250,8 +2375,7 @@ bool LLVivoxVoiceClient::addAndJoinSession(sessionState *nextSession)
// Terminating a half-connected session on other types of calls seems to break something in the vivox gateway.
if (mAudioSession->mIsP2P)
{
- sessionMediaDisconnectSendMessage(mAudioSession);
- setState(stateSessionTerminated);
+ terminateAudioSession(true);
return false;
}
}
@@ -2314,17 +2438,16 @@ bool LLVivoxVoiceClient::addAndJoinSession(sessionState *nextSession)
else if (!mVoiceEnabled && mIsInitialized)
{
// User bailed out during connect -- jump straight to teardown.
- setState(stateSessionTerminated);
+ terminateAudioSession(true);
return false;
}
else if (mSessionTerminateRequested)
{
- // Only allow direct exits from this state in p2p calls (for cancelling an invite).
+ // Only allow direct exits from this state in p2p calls (for canceling an invite).
// Terminating a half-connected session on other types of calls seems to break something in the vivox gateway.
if (mAudioSession && mAudioSession->mIsP2P)
{
- sessionMediaDisconnectSendMessage(mAudioSession);
- setState(stateSessionTerminated);
+ terminateAudioSession(true);
return false;
}
}
@@ -2332,7 +2455,215 @@ bool LLVivoxVoiceClient::addAndJoinSession(sessionState *nextSession)
}
+bool LLVivoxVoiceClient::terminateAudioSession(bool wait)
+{
+
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
+ if (mAudioSession)
+ {
+
+ if (!mAudioSession->mHandle.empty())
+ {
+
+#if RECORD_EVERYTHING
+ // HACK: for testing only
+ // Save looped recording
+ std::string savepath("/tmp/vivoxrecording");
+ {
+ time_t now = time(NULL);
+ const size_t BUF_SIZE = 64;
+ char time_str[BUF_SIZE]; /* Flawfinder: ignore */
+
+ strftime(time_str, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
+ savepath += time_str;
+ }
+ recordingLoopSave(savepath);
+#endif
+
+ sessionMediaDisconnectSendMessage(mAudioSession);
+
+ if (wait)
+ {
+ LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump");
+ LLSD result;
+ do
+ {
+ result = llcoro::suspendUntilEventOn(voicePump);
+
+ LL_INFOS("Voice") << "event=" << ll_pretty_print_sd(result) << LL_ENDL;
+ if (result.has("session"))
+ {
+ std::string message = result["session"].asString();
+ if (message == "removed")
+ break;
+ }
+ } while (true);
+
+ }
+ }
+ else
+ {
+ LL_WARNS("Voice") << "called with no session handle" << LL_ENDL;
+ }
+
+ sessionState *oldSession = mAudioSession;
+
+ mAudioSession = NULL;
+ // We just notified status observers about this change. Don't do it again.
+ mAudioSessionChanged = false;
+
+ // The old session may now need to be deleted.
+ reapSession(oldSession);
+
+ }
+ else
+ {
+ LL_WARNS("Voice") << "stateSessionTerminated with NULL mAudioSession" << LL_ENDL;
+ }
+ setState(stateSessionTerminated);
+
+ // Always reset the terminate request flag when we get here.
+ // Some slower PCs have a race condition where they can switch to an incoming P2P call faster than the state machine leaves
+ // the region chat.
+ mSessionTerminateRequested = false;
+
+ if ((mVoiceEnabled || !mIsInitialized) && !mRelogRequested && !LLApp::isExiting())
+ {
+ // Just leaving a channel, go back to stateNoChannel (the "logged in but have no channel" state).
+ setState(stateNoChannel);
+ return true;
+ }
+
+ return false;
+#if 0
+ //MARK: stateLeavingSession
+ case stateLeavingSession: // waiting for terminate session response
+ // The handler for the Session.Terminate response will transition from here to stateSessionTerminated.
+ //break; // Fall through and clean up session before getting terminated event.
+
+ //MARK: stateSessionTerminated
+ case stateSessionTerminated:
+
+ // Must do this first, since it uses mAudioSession.
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL);
+
+ if (mAudioSession && mSessionTerminateRequested)
+ {
+ // will only go this section on the frist frame when a call is being cancelled.
+ leaveAudioSession();
+ sessionState *oldSession = mAudioSession;
+
+ mAudioSession = NULL;
+ // We just notified status observers about this change. Don't do it again.
+ mAudioSessionChanged = false;
+
+ // The old session may now need to be deleted.
+ reapSession(oldSession);
+ }
+ else
+ {
+ LL_WARNS("Voice") << "stateSessionTerminated with NULL mAudioSession" << LL_ENDL;
+ }
+
+ // Always reset the terminate request flag when we get here.
+ // Some slower PCs have a race condition where they can switch to an incoming P2P call faster than the state machine leaves
+ // the region chat.
+ mSessionTerminateRequested = false;
+
+ if ((mVoiceEnabled || !mIsInitialized) && !mRelogRequested && !LLApp::isExiting())
+ {
+ // Just leaving a channel, go back to stateNoChannel (the "logged in but have no channel" state).
+ setState(stateNoChannel);
+ }
+ else
+ {
+ // Shutting down voice, continue with disconnecting.
+ logout();
+
+ // The state machine will take it from here
+ mRelogRequested = false;
+ }
+
+ break;
+#endif
+}
+
+bool LLVivoxVoiceClient::runSession(sessionState *session)
+{
+ if (!addAndJoinSession(session))
+ {
+ terminateAudioSession(true);
+
+ return false;
+ }
+
+ LLSD timeoutEvent = LLSD::emptyMap();
+ timeoutEvent["timeout"] = LLSD::Boolean(true);
+
+ LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump");
+ LLEventTimeout timeout(voicePump);
+
+ while (mVoiceEnabled && !mSessionTerminateRequested && !mTuningMode)
+ {
+ setState(stateRunning);
+
+ if (!inSpatialChannel())
+ {
+ // When in a non-spatial channel, never send positional updates.
+ mSpatialCoordsDirty = false;
+ }
+ else
+ {
+ updatePosition();
+
+ if (checkParcelChanged())
+ {
+ // if the parcel has changed, attempted to request the
+ // cap for the parcel voice info. If we can't request it
+ // then we don't have the cap URL so we do nothing and will
+ // recheck next time around
+ if (requestParcelVoiceInfo(stateRunning))
+ break;
+ }
+ // Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position)
+ enforceTether();
+ }
+
+ // Do notifications for expiring Voice Fonts.
+ if (mVoiceFontExpiryTimer.hasExpired())
+ {
+ expireVoiceFonts();
+ mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL);
+ }
+
+ // Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often
+ // -- the user can only click so fast) or every 10hz, whichever is sooner.
+ // Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged.
+ if ((mAudioSession && mAudioSession->mMuteDirty) || mMuteMicDirty)
+ {
+ mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
+ sendPositionalUpdate();
+ }
+ mIsInitialized = true;
+ timeout.eventAfter(UPDATE_THROTTLE_SECONDS, timeoutEvent);
+ LLSD result = llcoro::suspendUntilEventOn(timeout);
+
+ if (result.has("session"))
+ {
+ std::string message = result["session"];
+
+ if (message == "removed")
+ {
+ break;
+ }
+
+ }
+ }
+
+ terminateAudioSession(true);
+ return true;
+}
void LLVivoxVoiceClient::recordingAndPlaybackMode()
{
@@ -2785,6 +3116,7 @@ void LLVivoxVoiceClient::leaveAudioSession()
// Skip the join failed transition state so we don't send out error notifications.
setState(stateJoinSessionFailedWaiting);
break;
+#if 0
case stateJoiningSession:
case stateSessionJoined:
case stateRunning:
@@ -2822,6 +3154,7 @@ void LLVivoxVoiceClient::leaveAudioSession()
break;
case stateLeavingSession: // managed to get back to this case statement before the media gets disconnected.
break;
+#endif
default:
LL_WARNS("Voice") << "called from unknown state " << getState() << LL_ENDL;
@@ -4042,6 +4375,17 @@ void LLVivoxVoiceClient::sessionRemovedEvent(
// Already reaped this session.
LL_DEBUGS("Voice") << "unknown session " << sessionHandle << " removed" << LL_ENDL;
}
+#if 1
+ LLSD vivoxevent = LLSD::emptyMap();
+
+ vivoxevent["session"] = LLSD::String("removed");
+
+ LLEventPumps::instance().post("vivoxClientPump", vivoxevent);
+
+#else
+ setState(stateSessionJoined);
+#endif
+
}
void LLVivoxVoiceClient::reapSession(sessionState *session)
@@ -4969,7 +5313,7 @@ bool LLVivoxVoiceClient::parcelVoiceInfoReceived(state requesting_state)
}
}
-
+#if 0
bool LLVivoxVoiceClient::requestParcelVoiceInfo()
{
LLViewerRegion * region = gAgent.getRegion();
@@ -5052,8 +5396,9 @@ void LLVivoxVoiceClient::parcelVoiceInfoRequestCoro(std::string url)
}
}
+#endif
-void LLVivoxVoiceClient::switchChannel(
+bool LLVivoxVoiceClient::switchChannel(
std::string uri,
bool spatial,
bool no_reconnect,
@@ -5153,6 +5498,8 @@ void LLVivoxVoiceClient::switchChannel(
sessionTerminate();
}
}
+
+ return needsSwitch;
}
void LLVivoxVoiceClient::joinSession(sessionState *session)
@@ -5177,7 +5524,7 @@ void LLVivoxVoiceClient::setNonSpatialChannel(
switchChannel(uri, false, false, false, credentials);
}
-void LLVivoxVoiceClient::setSpatialChannel(
+bool LLVivoxVoiceClient::setSpatialChannel(
const std::string &uri,
const std::string &credentials)
{
@@ -5191,10 +5538,11 @@ void LLVivoxVoiceClient::setSpatialChannel(
{
// User is in a non-spatial chat or joining a non-spatial chat. Don't switch channels.
LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL;
+ return false;
}
else
{
- switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
+ return switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
}
}
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index dd9fcd4344..a4d6f38157 100755
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -138,7 +138,7 @@ public:
virtual void setNonSpatialChannel(const std::string &uri,
const std::string &credentials);
- virtual void setSpatialChannel(const std::string &uri,
+ virtual bool setSpatialChannel(const std::string &uri,
const std::string &credentials);
virtual void leaveNonSpatialChannel();
@@ -640,7 +640,7 @@ protected:
private:
// void voiceAccountProvisionCoro(std::string url, S32 retries);
- void parcelVoiceInfoRequestCoro(std::string url);
+// void parcelVoiceInfoRequestCoro(std::string url);
LLVoiceVersionInfo mVoiceVersion;
@@ -653,7 +653,12 @@ private:
bool loginToVivox();
bool retrieveVoiceFonts();
+ bool requestParcelVoiceInfo(state exitState);
+
bool addAndJoinSession(sessionState *nextSession);
+ bool terminateAudioSession(bool wait);
+
+ bool runSession(sessionState *session);
void recordingAndPlaybackMode();
int voiceRecordBuffer();
@@ -755,9 +760,11 @@ private:
bool checkParcelChanged(bool update = false);
// This should be called when the code detects we have changed parcels.
// It initiates the call to the server that gets the parcel channel.
+#if 0
bool requestParcelVoiceInfo();
-
- void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
+#endif
+
+ bool switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
void joinSession(sessionState *session);
std::string nameFromAvatar(LLVOAvatar *avatar);