diff options
Diffstat (limited to 'indra/newview/llvoiceclient.h')
-rw-r--r-- | indra/newview/llvoiceclient.h | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h new file mode 100644 index 0000000000..d45b113e63 --- /dev/null +++ b/indra/newview/llvoiceclient.h @@ -0,0 +1,503 @@ +/** + * @file llvoiceclient.h + * @brief Declaration of LLVoiceClient class which is the interface to the voice client process. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ +#ifndef LL_VOICE_CLIENT_H +#define LL_VOICE_CLIENT_H + +// This would create a circular reference -- just do a forward definition of necessary class names. +//#include "llvoavatar.h" +class LLVOAvatar; +class LLVivoxProtocolParser; + +#include "lliopipe.h" +#include "llpumpio.h" +#include "llchainio.h" +#include "lliosocket.h" +#include "v3math.h" +#include "llframetimer.h" +#include "llviewerregion.h" + +class LLVoiceClientParticipantObserver +{ +public: + virtual ~LLVoiceClientParticipantObserver() { } + virtual void onChange() = 0; +}; + +class LLVoiceClientStatusObserver +{ +public: + typedef enum e_voice_status_type + { + STATUS_LOGIN_RETRY, + STATUS_LOGGED_IN, + STATUS_JOINING, + STATUS_JOINED, + STATUS_LEFT_CHANNEL, + BEGIN_ERROR_STATUS, + ERROR_CHANNEL_FULL, + ERROR_CHANNEL_LOCKED, + ERROR_NOT_AVAILABLE, + ERROR_UNKNOWN + } EStatusType; + + virtual ~LLVoiceClientStatusObserver() { } + virtual void onChange(EStatusType status, const std::string &channelURI, bool proximal) = 0; + + static const char *status2string(EStatusType inStatus); +}; + +class LLVoiceClient: public LLSingleton<LLVoiceClient> +{ + LOG_CLASS(LLVoiceClient); + public: + LLVoiceClient(); + ~LLVoiceClient(); + + public: + static void init(LLPumpIO *pump); // Call this once at application startup (creates connector) + static void terminate(); // Call this to clean up during shutdown + + protected: + bool writeString(const std::string &str); + + public: + + enum serviceType + { + serviceTypeUnknown, // Unknown, returned if no data on the avatar is available + serviceTypeA, // spatialized local chat + serviceTypeB, // remote multi-party chat + serviceTypeC // one-to-one and small group chat + }; + static F32 OVERDRIVEN_POWER_LEVEL; + + ///////////////////////////// + // session control messages + void connect(); + + void connectorCreate(); + void connectorShutdown(); + + void requestVoiceAccountProvision(S32 retries = 3); + void userAuthorized( + const std::string& firstName, + const std::string& lastName, + const LLUUID &agentID); + void login(const std::string& accountName, const std::string &password); + void loginSendMessage(); + void logout(); + void logoutSendMessage(); + + void channelGetListSendMessage(); + void sessionCreateSendMessage(); + void sessionConnectSendMessage(); + void sessionTerminate(); + void sessionTerminateSendMessage(); + void sessionTerminateByHandle(std::string &sessionHandle); + + void getCaptureDevicesSendMessage(); + void getRenderDevicesSendMessage(); + + void clearCaptureDevices(); + void addCaptureDevice(const std::string& name); + void setCaptureDevice(const std::string& name); + + void clearRenderDevices(); + void addRenderDevice(const std::string& name); + void setRenderDevice(const std::string& name); + + void tuningStart(); + void tuningStop(); + bool inTuningMode(); + + void tuningRenderStartSendMessage(const std::string& name, bool loop); + void tuningRenderStopSendMessage(); + + void tuningCaptureStartSendMessage(int duration); + void tuningCaptureStopSendMessage(); + + void tuningSetMicVolume(float volume); + void tuningSetSpeakerVolume(float volume); + float tuningGetEnergy(void); + + // This returns true when it's safe to bring up the "device settings" dialog in the prefs. + // i.e. when the daemon is running and connected, and the device lists are populated. + bool deviceSettingsAvailable(); + + // Requery the vivox daemon for the current list of input/output devices. + // If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed + // (use this if you want to know when it's done). + // If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim. + void refreshDeviceLists(bool clearCurrentList = true); + + // Call this if the connection to the daemon terminates unexpectedly. It will attempt to reset everything and relaunch. + void daemonDied(); + + // Call this if we're just giving up on voice (can't provision an account, etc.). It will clean up and go away. + void giveUp(); + + ///////////////////////////// + // Response/Event handlers + void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle); + void loginResponse(int statusCode, std::string &statusString, std::string &accountHandle); + void channelGetListResponse(int statusCode, std::string &statusString); + void sessionCreateResponse(int statusCode, std::string &statusString, std::string &sessionHandle); + void sessionConnectResponse(int statusCode, std::string &statusString); + void sessionTerminateResponse(int statusCode, std::string &statusString); + void logoutResponse(int statusCode, std::string &statusString); + void connectorShutdownResponse(int statusCode, std::string &statusString); + + void loginStateChangeEvent(std::string &accountHandle, int statusCode, std::string &statusString, int state); + void sessionNewEvent(std::string &accountHandle, std::string &eventSessionHandle, int state, std::string &nameString, std::string &uriString); + void sessionStateChangeEvent(std::string &uriString, int statusCode, std::string &statusString, std::string &sessionHandle, int state, bool isChannel, std::string &nameString); + void participantStateChangeEvent(std::string &uriString, int statusCode, std::string &statusString, int state, std::string &nameString, std::string &displayNameString, int participantType); + void participantPropertiesEvent(std::string &uriString, int statusCode, std::string &statusString, bool isLocallyMuted, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy); + void auxAudioPropertiesEvent(F32 energy); + + void muteListChanged(); + + ///////////////////////////// + // Sending updates of current state + void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot); + void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot); + bool channelFromRegion(LLViewerRegion *region, std::string &name); + void leaveChannel(void); // call this on logout or teleport begin + + + void setMuteMic(bool muted); // Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state. + void setUserPTTState(bool ptt); + bool getUserPTTState(); + void toggleUserPTTState(void); + void setVoiceEnabled(bool enabled); + static bool voiceEnabled(); + void setUsePTT(bool usePTT); + void setPTTIsToggle(bool PTTIsToggle); + void setPTTKey(std::string &key); + void setEarLocation(S32 loc); + void setVoiceVolume(F32 volume); + void setMicGain(F32 volume); + void setUserVolume(const LLUUID& id, F32 volume); // set's volume for specified agent, from 0-1 (where .5 is nominal) + void setVivoxDebugServerName(std::string &serverName); + + // PTT key triggering + void keyDown(KEY key, MASK mask); + void keyUp(KEY key, MASK mask); + void middleMouseState(bool down); + + ///////////////////////////// + // Accessors for data related to nearby speakers + BOOL getVoiceEnabled(const LLUUID& id); // true if we've received data for this avatar + BOOL getIsSpeaking(const LLUUID& id); + F32 getCurrentPower(const LLUUID& id); // "power" is related to "amplitude" in a defined way. I'm just not sure what the formula is... + BOOL getPTTPressed(const LLUUID& id); // This is the inverse of the "locally muted" property. + BOOL getOnMuteList(const LLUUID& id); + F32 getUserVolume(const LLUUID& id); + LLString getDisplayName(const LLUUID& id); + + // MBW -- XXX -- Not sure how to get this data out of the TVC + BOOL getUsingPTT(const LLUUID& id); + serviceType getServiceType(const LLUUID& id); // type of chat the user is involved in (see bHear scope doc for definitions of A/B/C) + std::string getGroupID(const LLUUID& id); // group ID if the user is in group chat (empty string if not applicable) + + ///////////////////////////// + BOOL getAreaVoiceDisabled(); // returns true if the area the avatar is in is speech-disabled. + // Use this to determine whether to show a "no speech" icon in the menu bar. + + struct participantState + { + public: + participantState(const std::string &uri); + std::string mURI; + std::string mName; + std::string mDisplayName; + bool mPTT; + bool mIsSpeaking; + LLFrameTimer mSpeakingTimeout; + F32 mLastSpokeTimestamp; + F32 mPower; + int mVolume; + serviceType mServiceType; + std::string mGroupID; + bool mOnMuteList; // true if this avatar is on the user's mute list (and should be muted) + int mUserVolume; + bool mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed) + bool mAvatarIDValid; + LLUUID mAvatarID; + }; + typedef std::map<std::string, participantState*> participantMap; + + participantState *findParticipant(const std::string &uri); + participantState *findParticipantByAvatar(LLVOAvatar *avatar); + participantState *findParticipantByID(const LLUUID& id); + + participantMap *getParticipantList(void); + + void addObserver(LLVoiceClientParticipantObserver* observer); + void removeObserver(LLVoiceClientParticipantObserver* observer); + + void addStatusObserver(LLVoiceClientStatusObserver* observer); + void removeStatusObserver(LLVoiceClientStatusObserver* observer); + + static void onAvatarNameLookup(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* user_data); + typedef std::vector<std::string> deviceList; + + deviceList *getCaptureDevices(); + deviceList *getRenderDevices(); + + void setNonSpatialChannel( + const std::string &uri, + const std::string &credentials); + void setSpatialChannel( + const std::string &uri, + const std::string &credentials); + void callUser(LLUUID &uuid); + void answerInvite(std::string &sessionHandle, LLUUID& other_user_id); + void declineInvite(std::string &sessionHandle); + void leaveNonSpatialChannel(); + + // Returns the URI of the current channel, or an empty string if not currently in a channel. + // NOTE that it will return an empty string if it's in the process of joining a channel. + std::string getCurrentChannel(); + + // returns true iff the user is currently in a proximal (local spatial) channel. + // Note that gestures should only fire if this returns true. + bool inProximalChannel(); + + std::string sipURIFromID(const LLUUID &id); + + private: + + // internal state for a simple state machine. This is used to deal with the asynchronous nature of some of the messages. + // Note: if you change this list, please make corresponding changes to LLVoiceClient::state2string(). + enum state + { + stateDisabled, // Voice is turned off. + stateStart, // Class is initialized, socket is created + stateDaemonLaunched, // Daemon has been launched + stateConnecting, // connect() call has been issued + stateIdle, // socket is connected, ready for messaging + stateConnectorStart, // connector needs to be started + stateConnectorStarting, // waiting for connector handle + stateConnectorStarted, // connector handle received + stateMicTuningNoLogin, // mic tuning before login + stateLoginRetry, // need to retry login (failed due to changing password) + stateLoginRetryWait, // waiting for retry timer + stateNeedsLogin, // send login request + stateLoggingIn, // waiting for account handle + stateLoggedIn, // account handle received + stateNoChannel, // + stateMicTuningLoggedIn, // mic tuning for a logged in user + stateSessionCreate, // need to send Session.Create command + stateSessionConnect, // need to send Session.Connect command + stateJoiningSession, // waiting for session handle + stateSessionJoined, // session handle received + stateRunning, // in session, steady state + stateLeavingSession, // waiting for terminate session response + stateSessionTerminated, // waiting for terminate session response + + stateLoggingOut, // waiting for logout response + stateLoggedOut, // logout response received + stateConnectorStopping, // waiting for connector stop + stateConnectorStopped, // connector stop received + + // We go to this state if the login fails because the account needs to be provisioned. + + // error states. No way to recover from these yet. + stateConnectorFailed, + stateConnectorFailedWaiting, + stateLoginFailed, + stateLoginFailedWaiting, + stateJoinSessionFailed, + stateJoinSessionFailedWaiting, + + stateJail // Go here when all else has failed. Nothing will be retried, we're done. + }; + + state mState; + bool mSessionTerminateRequested; + bool mNonSpatialChannel; + + void setState(state inState); + state getState(void) { return mState; }; + static const char *state2string(state inState); + + void stateMachine(); + static void idle(void *user_data); + + LLHost mDaemonHost; + LLSocket::ptr_t mSocket; + bool mConnected; + + void closeSocket(void); + + LLPumpIO *mPump; + friend class LLVivoxProtocolParser; + + std::string mAccountName; + std::string mAccountPassword; + std::string mAccountDisplayName; + std::string mAccountFirstName; + std::string mAccountLastName; + + std::string mNextP2PSessionURI; // URI of the P2P session to join next + std::string mNextSessionURI; // URI of the session to join next + std::string mNextSessionHandle; // Session handle of the session to join next + std::string mNextSessionHash; // Password hash for the session to join next + bool mNextSessionSpatial; // Will next session be a spatial chat? + bool mNextSessionNoReconnect; // Next session should not auto-reconnect (i.e. user -> user chat) + bool mNextSessionResetOnClose; // If this is true, go back to spatial chat when the next session terminates. + + std::string mSessionStateEventHandle; // session handle received in SessionStateChangeEvents + std::string mSessionStateEventURI; // session URI received in SessionStateChangeEvents + + bool mTuningMode; + float mTuningEnergy; + std::string mTuningAudioFile; + int mTuningMicVolume; + bool mTuningMicVolumeDirty; + int mTuningSpeakerVolume; + bool mTuningSpeakerVolumeDirty; + bool mTuningCaptureRunning; + + std::string mSpatialSessionURI; + + bool mSessionResetOnClose; + + int mVivoxErrorStatusCode; + std::string mVivoxErrorStatusString; + + std::string mChannelName; // Name of the channel to be looked up + bool mAreaVoiceDisabled; + std::string mSessionURI; // URI of the session we're in. + bool mSessionP2P; // true if this session is a p2p call + + S32 mCurrentParcelLocalID; // Used to detect parcel boundary crossings + std::string mCurrentRegionName; // Used to detect parcel boundary crossings + + std::string mConnectorHandle; // returned by "Create Connector" message + std::string mAccountHandle; // returned by login message + std::string mSessionHandle; // returned by ? + U32 mCommandCookie; + + std::string mAccountServerName; + std::string mAccountServerURI; + + int mLoginRetryCount; + + participantMap mParticipantMap; + bool mParticipantMapChanged; + + deviceList mCaptureDevices; + deviceList mRenderDevices; + + std::string mCaptureDevice; + std::string mRenderDevice; + bool mCaptureDeviceDirty; + bool mRenderDeviceDirty; + + participantState *addParticipant(const std::string &uri); + // Note: after removeParticipant returns, the participant* that was passed to it will have been deleted. + // Take care not to use the pointer again after that. + void removeParticipant(participantState *participant); + void removeAllParticipants(); + + void updateMuteState(participantState *participant); + + typedef std::map<std::string, std::string> channelMap; + channelMap mChannelMap; + + // These are used by the parser when processing a channel list response. + void clearChannelMap(void); + void addChannelMapEntry(std::string &name, std::string &uri); + std::string findChannelURI(std::string &name); + + // This should be called when the code detects we have changed parcels. + // It initiates the call to the server that gets the parcel channel. + void parcelChanged(); + + void switchChannel(std::string uri = "", bool spatial = true, bool noReconnect = false, std::string hash = ""); + void joinSession(std::string handle, std::string uri); + + std::string nameFromAvatar(LLVOAvatar *avatar); + std::string nameFromID(const LLUUID &id); + bool IDFromName(const std::string name, LLUUID &uuid); + std::string displayNameFromAvatar(LLVOAvatar *avatar); + std::string sipURIFromAvatar(LLVOAvatar *avatar); + std::string sipURIFromName(std::string &name); + + void sendPositionalUpdate(void); + + void buildSetCaptureDevice(std::ostringstream &stream); + void buildSetRenderDevice(std::ostringstream &stream); + + void enforceTether(void); + + bool mSpatialCoordsDirty; + + LLVector3d mCameraPosition; + LLVector3d mCameraRequestedPosition; + LLVector3 mCameraVelocity; + LLMatrix3 mCameraRot; + + LLVector3d mAvatarPosition; + LLVector3 mAvatarVelocity; + LLMatrix3 mAvatarRot; + + bool mPTTDirty; + bool mPTT; + + bool mUsePTT; + bool mPTTIsMiddleMouse; + KEY mPTTKey; + bool mPTTIsToggle; + bool mUserPTTState; + bool mMuteMic; + + // Set to true when the mute state of someone in the participant list changes. + // The code will have to walk the list to find the changed participant(s). + bool mVolumeDirty; + + enum + { + earLocCamera = 0, // ear at camera + earLocAvatar, // ear at avatar + earLocMixed // ear at avatar location/camera direction + }; + + S32 mEarLocation; + + bool mSpeakerVolumeDirty; + bool mSpeakerMuteDirty; + int mSpeakerVolume; + + int mMicVolume; + bool mMicVolumeDirty; + + bool mVoiceEnabled; + bool mWriteInProgress; + std::string mWriteString; + size_t mWriteOffset; + + LLTimer mUpdateTimer; + + typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t; + observer_set_t mObservers; + + void notifyObservers(); + + typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t; + status_observer_set_t mStatusObservers; + + void notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status); +}; + +extern LLVoiceClient *gVoiceClient; + +#endif //LL_VOICE_CLIENT_H + + |