diff options
| author | Rider Linden <rider@lindenlab.com> | 2015-12-09 16:33:51 -0800 | 
|---|---|---|
| committer | Rider Linden <rider@lindenlab.com> | 2015-12-09 16:33:51 -0800 | 
| commit | 7e58b0793b021922e68e10f111d624bb7638fefa (patch) | |
| tree | 82ae16d24920f1684b9d477ed351fe2f876c6ab7 /indra/newview | |
| parent | aa67a2fba05a703364e91d034d4b9a2f5d2f26e2 (diff) | |
Voice session state now in coro (includes all sub states as part of the coro)
Diffstat (limited to 'indra/newview')
| -rwxr-xr-x | indra/newview/llvoiceclient.h | 2 | ||||
| -rwxr-xr-x | indra/newview/llvoicevivox.cpp | 384 | ||||
| -rwxr-xr-x | indra/newview/llvoicevivox.h | 15 | 
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); | 
