diff options
author | Roxie Linden <roxie@lindenlab.com> | 2023-09-06 15:28:02 -0700 |
---|---|---|
committer | Roxie Linden <roxie@lindenlab.com> | 2024-02-08 18:34:00 -0800 |
commit | 0ae8bbaf5d85b065354dcc010d08a4a2e759f867 (patch) | |
tree | 69c952c2cca7f793e1cfc5b51669882879b1ac4d /indra/newview/llvoicewebrtc.h | |
parent | e2ba2f9c453d4e913b0deb5dfee2a07c55034655 (diff) |
Checkpoint WebRTC Voice
Diffstat (limited to 'indra/newview/llvoicewebrtc.h')
-rw-r--r-- | indra/newview/llvoicewebrtc.h | 1102 |
1 files changed, 1102 insertions, 0 deletions
diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h new file mode 100644 index 0000000000..56ca74f6e1 --- /dev/null +++ b/indra/newview/llvoicewebrtc.h @@ -0,0 +1,1102 @@ +/** + * @file llvoicewebrtc.h + * @brief Declaration of LLWebRTCVoiceClient class which is the interface to the voice client process. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#ifndef LL_VOICE_WEBRTC_H +#define LL_VOICE_WEBRTC_H + +class LLVOAvatar; +class LLWebRTCProtocolParser; + +#include "lliopipe.h" +#include "llpumpio.h" +#include "llchainio.h" +#include "lliosocket.h" +#include "v3math.h" +#include "llframetimer.h" +#include "llviewerregion.h" +#include "llcallingcard.h" // for LLFriendObserver +#include "lleventcoro.h" +#include "llcoros.h" +#include <queue> + +#ifdef LL_USESYSTEMLIBS +# include "expat.h" +#else +# include "expat/expat.h" +#endif +#include "llvoiceclient.h" + +// WebRTC Includes +#include <llwebrtc.h> + +class LLAvatarName; +class LLWebRTCVoiceClientMuteListObserver; + + +class LLWebRTCVoiceClient : public LLSingleton<LLWebRTCVoiceClient>, + virtual public LLVoiceModuleInterface, + virtual public LLVoiceEffectInterface, + public llwebrtc::LLWebRTCDevicesObserver, + public llwebrtc::LLWebRTCSignalingObserver +{ + LLSINGLETON(LLWebRTCVoiceClient); + LOG_CLASS(LLWebRTCVoiceClient); + virtual ~LLWebRTCVoiceClient(); + +public: + /// @name LLVoiceModuleInterface virtual implementations + /// @see LLVoiceModuleInterface + //@{ + virtual void init(LLPumpIO *pump); // Call this once at application startup (creates connector) + virtual void terminate(); // Call this to clean up during shutdown + + virtual const LLVoiceVersionInfo& getVersion(); + + virtual void updateSettings(); // call after loading settings and whenever they change + + // Returns true if WebRTC has successfully logged in and is not in error state + virtual bool isVoiceWorking() const; + + ///////////////////// + /// @name Tuning + //@{ + virtual void tuningStart(); + virtual void tuningStop(); + virtual bool inTuningMode(); + + virtual void tuningSetMicVolume(float volume); + virtual void tuningSetSpeakerVolume(float volume); + virtual float tuningGetEnergy(void); + //@} + + ///////////////////// + /// @name Devices + //@{ + // 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. + virtual bool deviceSettingsAvailable(); + virtual bool deviceSettingsUpdated(); //return if the list has been updated and never fetched, only to be called from the voicepanel. + + // Requery the WebRTC 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. + virtual void refreshDeviceLists(bool clearCurrentList = true); + + virtual void setCaptureDevice(const std::string& name); + virtual void setRenderDevice(const std::string& name); + + virtual LLVoiceDeviceList& getCaptureDevices(); + virtual LLVoiceDeviceList& getRenderDevices(); + //@} + + virtual void getParticipantList(std::set<LLUUID> &participants); + virtual bool isParticipant(const LLUUID& speaker_id); + + // Send a text message to the specified user, initiating the session if necessary. + // virtual BOOL sendTextMessage(const LLUUID& participant_id, const std::string& message) const {return false;}; + + // close any existing text IM session with the specified user + virtual void endUserIMSession(const LLUUID &uuid); + + // Returns true if calling back the session URI after the session has closed is possible. + // Currently this will be false only for PSTN P2P calls. + // NOTE: this will return true if the session can't be found. + virtual BOOL isSessionCallBackPossible(const LLUUID &session_id); + + // Returns true if the session can accepte text IM's. + // Currently this will be false only for PSTN P2P calls. + // NOTE: this will return true if the session can't be found. + virtual BOOL isSessionTextIMPossible(const LLUUID &session_id); + + + //////////////////////////// + /// @name Channel stuff + //@{ + // returns true iff the user is currently in a proximal (local spatial) channel. + // Note that gestures should only fire if this returns true. + virtual bool inProximalChannel(); + + virtual void setNonSpatialChannel(const std::string &uri, + const std::string &credentials); + + virtual bool setSpatialChannel(const std::string &uri, + const std::string &credentials); + + virtual void leaveNonSpatialChannel(); + + virtual void leaveChannel(void); + + // 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. + virtual std::string getCurrentChannel(); + //@} + + + ////////////////////////// + /// @name invitations + //@{ + // start a voice channel with the specified user + virtual void callUser(const LLUUID &uuid); + virtual bool isValidChannel(std::string &channelHandle); + virtual bool answerInvite(std::string &channelHandle); + virtual void declineInvite(std::string &channelHandle); + //@} + + ///////////////////////// + /// @name Volume/gain + //@{ + virtual void setVoiceVolume(F32 volume); + virtual void setMicGain(F32 volume); + //@} + + ///////////////////////// + /// @name enable disable voice and features + //@{ + virtual bool voiceEnabled(); + virtual void setVoiceEnabled(bool enabled); + virtual BOOL lipSyncEnabled(); + virtual void setLipSyncEnabled(BOOL enabled); + virtual void setMuteMic(bool muted); // Set the mute state of the local mic. + //@} + + ////////////////////////// + /// @name nearby speaker accessors + //@{ + virtual BOOL getVoiceEnabled(const LLUUID& id); // true if we've received data for this avatar + virtual std::string getDisplayName(const LLUUID& id); + virtual BOOL isParticipantAvatar(const LLUUID &id); + virtual BOOL getIsSpeaking(const LLUUID& id); + virtual BOOL getIsModeratorMuted(const LLUUID& id); + virtual F32 getCurrentPower(const LLUUID& id); // "power" is related to "amplitude" in a defined way. I'm just not sure what the formula is... + virtual BOOL getOnMuteList(const LLUUID& id); + virtual F32 getUserVolume(const LLUUID& id); + virtual void setUserVolume(const LLUUID& id, F32 volume); // set's volume for specified agent, from 0-1 (where .5 is nominal) + //@} + + // authorize the user + virtual void userAuthorized(const std::string& user_id, + const LLUUID &agentID); + + ////////////////////////////// + /// @name Status notification + //@{ + virtual void addObserver(LLVoiceClientStatusObserver* observer); + virtual void removeObserver(LLVoiceClientStatusObserver* observer); + virtual void addObserver(LLFriendObserver* observer); + virtual void removeObserver(LLFriendObserver* observer); + virtual void addObserver(LLVoiceClientParticipantObserver* observer); + virtual void removeObserver(LLVoiceClientParticipantObserver* observer); + //@} + + virtual std::string sipURIFromID(const LLUUID &id); + //@} + + /// @name LLVoiceEffectInterface virtual implementations + /// @see LLVoiceEffectInterface + //@{ + + ////////////////////////// + /// @name Accessors + //@{ + virtual bool setVoiceEffect(const LLUUID& id); + virtual const LLUUID getVoiceEffect(); + virtual LLSD getVoiceEffectProperties(const LLUUID& id); + + virtual void refreshVoiceEffectLists(bool clear_lists); + virtual const voice_effect_list_t& getVoiceEffectList() const; + virtual const voice_effect_list_t& getVoiceEffectTemplateList() const; + //@} + + ////////////////////////////// + /// @name Status notification + //@{ + virtual void addObserver(LLVoiceEffectObserver* observer); + virtual void removeObserver(LLVoiceEffectObserver* observer); + //@} + + ////////////////////////////// + /// @name Devices change notification + // LLWebRTCDevicesObserver + //@{ + void OnRenderDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices) override; + void OnCaptureDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices) override; + //@} + + ////////////////////////////// + /// @name Signaling notification + // LLWebRTCSignalingObserver + //@{ + void OnIceGatheringState(IceGatheringState state) override; + void OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate &candidate) override; + void OnOfferAvailable(const std::string &sdp) override; + void OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface *audio_interface) override; + //@} + + void processIceUpdates(); + void onIceUpdateComplete(const LLSD& result); + void onIceUpdateError(int retries, std::string url, LLSD body, const LLSD& result); + + + ////////////////////////////// + /// @name Effect preview buffer + //@{ + virtual void enablePreviewBuffer(bool enable); + virtual void recordPreviewBuffer(); + virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null); + virtual void stopPreviewBuffer(); + + virtual bool isPreviewRecording(); + virtual bool isPreviewPlaying(); + //@} + + //@} + + bool onCheckVoiceEffect(const std::string& voice_effect_name); + void onClickVoiceEffect(const std::string& voice_effect_name); + +protected: + ////////////////////// + // WebRTC Specific definitions + + friend class LLWebRTCVoiceClientMuteListObserver; + friend class LLWebRTCVoiceClientFriendsObserver; + + + enum streamState + { + streamStateUnknown = 0, + streamStateIdle = 1, + streamStateConnected = 2, + streamStateRinging = 3, + streamStateConnecting = 6, // same as WebRTC session_media_connecting enum + streamStateDisconnecting = 7, //Same as WebRTC session_media_disconnecting enum + }; + + struct participantState + { + public: + participantState(const std::string &uri); + + bool updateMuteState(); // true if mute state has changed + bool isAvatar(); + + std::string mURI; + LLUUID mAvatarID; + std::string mAccountName; + std::string mDisplayName; + LLFrameTimer mSpeakingTimeout; + F32 mLastSpokeTimestamp; + F32 mPower; + F32 mVolume; + std::string mGroupID; + int mUserVolume; + bool mPTT; + bool mIsSpeaking; + bool mIsModeratorMuted; + bool mOnMuteList; // true if this avatar is on the user's mute list (and should be muted) + bool mVolumeSet; // true if incoming volume messages should not change the volume + bool mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed) + bool mAvatarIDValid; + bool mIsSelf; + }; + typedef boost::shared_ptr<participantState> participantStatePtr_t; + typedef boost::weak_ptr<participantState> participantStateWptr_t; + + typedef std::map<const std::string, participantStatePtr_t> participantMap; + typedef std::map<const LLUUID, participantStatePtr_t> participantUUIDMap; + + struct sessionState + { + public: + typedef boost::shared_ptr<sessionState> ptr_t; + typedef boost::weak_ptr<sessionState> wptr_t; + + typedef boost::function<void(const ptr_t &)> sessionFunc_t; + + static ptr_t createSession(); + ~sessionState(); + + participantStatePtr_t addParticipant(const std::string &uri); + void removeParticipant(const participantStatePtr_t &participant); + void removeAllParticipants(); + + participantStatePtr_t findParticipant(const std::string &uri); + participantStatePtr_t findParticipantByID(const LLUUID& id); + + static ptr_t matchSessionByHandle(const std::string &handle); + static ptr_t matchCreatingSessionByURI(const std::string &uri); + static ptr_t matchSessionByURI(const std::string &uri); + static ptr_t matchSessionByParticipant(const LLUUID &participant_id); + + bool isCallBackPossible(); + bool isTextIMPossible(); + + static void for_each(sessionFunc_t func); + + std::string mHandle; + std::string mGroupHandle; + std::string mSIPURI; + std::string mAlias; + std::string mName; + std::string mAlternateSIPURI; + std::string mHash; // Channel password + std::string mErrorStatusString; + std::queue<std::string> mTextMsgQueue; + + LLUUID mIMSessionID; + LLUUID mCallerID; + int mErrorStatusCode; + int mMediaStreamState; + bool mCreateInProgress; // True if a Session.Create has been sent for this session and no response has been received yet. + bool mMediaConnectInProgress; // True if a Session.MediaConnect has been sent for this session and no response has been received yet. + bool mVoiceInvitePending; // True if a voice invite is pending for this session (usually waiting on a name lookup) + bool mTextInvitePending; // True if a text invite is pending for this session (usually waiting on a name lookup) + bool mSynthesizedCallerID; // True if the caller ID is a hash of the SIP URI -- this means we shouldn't do a name lookup. + bool mIsChannel; // True for both group and spatial channels (false for p2p, PSTN) + bool mIsSpatial; // True for spatial channels + bool mIsP2P; + bool mIncoming; + bool mVoiceActive; + bool mReconnect; // Whether we should try to reconnect to this session if it's dropped + + // Set to true when the volume/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; + bool mMuteDirty; + + bool mParticipantsChanged; + participantMap mParticipantsByURI; + participantUUIDMap mParticipantsByUUID; + + LLUUID mVoiceFontID; + + static void VerifySessions(); + + private: + sessionState(); + + static std::set<wptr_t> mSession; // canonical list of outstanding sessions. + std::set<wptr_t>::iterator mMyIterator; // used for delete + + static void for_eachPredicate(const wptr_t &a, sessionFunc_t func); + + static bool testByHandle(const LLWebRTCVoiceClient::sessionState::wptr_t &a, std::string handle); + static bool testByCreatingURI(const LLWebRTCVoiceClient::sessionState::wptr_t &a, std::string uri); + static bool testBySIPOrAlterateURI(const LLWebRTCVoiceClient::sessionState::wptr_t &a, std::string uri); + static bool testByCallerId(const LLWebRTCVoiceClient::sessionState::wptr_t &a, LLUUID participantId); + + }; + typedef boost::shared_ptr<sessionState> sessionStatePtr_t; + + typedef std::map<std::string, sessionStatePtr_t> sessionMap; + + /////////////////////////////////////////////////////// + // Private Member Functions + ////////////////////////////////////////////////////// + + + + ////////////////////////////// + /// @name TVC/Server management and communication + //@{ + // 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(); + + // write to the tvc + bool writeString(const std::string &str); + + void connectorCreate(); + void connectorShutdown(); + void closeSocket(void); + +// void requestVoiceAccountProvision(S32 retries = 3); + void setLoginInfo( + const std::string& account_name, + const std::string& password, + const std::string& channel_sdp); + void loginSendMessage(); + void logout(); + void logoutSendMessage(); + + + //@} + + //------------------------------------ + // tuning + + void tuningRenderStartSendMessage(const std::string& name, bool loop); + void tuningRenderStopSendMessage(); + + void tuningCaptureStartSendMessage(int duration); + void tuningCaptureStopSendMessage(); + + //---------------------------------- + // devices + void clearCaptureDevices(); + void addCaptureDevice(const LLVoiceDevice& device); + + void clearRenderDevices(); + void addRenderDevice(const LLVoiceDevice& device); + void setDevicesListUpdated(bool state); + void buildSetAudioDevices(std::ostringstream &stream); + + // local audio updates, mic mute, speaker mute, mic volume and speaker volumes + void sendLocalAudioUpdates(); + + ///////////////////////////// + // Response/Event handlers + void connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID); + void loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases); + void sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle); + void sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle); + void sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString); + void logoutResponse(int statusCode, std::string &statusString); + void connectorShutdownResponse(int statusCode, std::string &statusString); + + void accountLoginStateChangeEvent(std::string &accountHandle, int statusCode, std::string &statusString, int state); + void mediaCompletionEvent(std::string &sessionGroupHandle, std::string &mediaCompletionType); + void mediaStreamUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, int statusCode, std::string &statusString, int state, bool incoming); + void sessionAddedEvent(std::string &uriString, std::string &alias, std::string &sessionHandle, std::string &sessionGroupHandle, bool isChannel, bool incoming, std::string &nameString, std::string &applicationString); + void sessionGroupAddedEvent(std::string &sessionGroupHandle); + void sessionRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle); + void participantAddedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString, std::string &displayNameString, int participantType); + void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString); + void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy); + void voiceServiceConnectionStateChangedEvent(int statusCode, std::string &statusString, std::string &build_id); + void auxAudioPropertiesEvent(F32 energy); + void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString); + void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string ¬ificationType); + + void muteListChanged(); + + ///////////////////////////// + // VAD changes + // disable auto-VAD and configure VAD parameters explicitly + void setupVADParams(unsigned int vad_auto, unsigned int vad_hangover, unsigned int vad_noise_floor, unsigned int vad_sensitivity); + void onVADSettingsChange(); + + ///////////////////////////// + // Sending updates of current state + void updatePosition(void); + void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot); + void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot); + bool channelFromRegion(LLViewerRegion *region, std::string &name); + + void setEarLocation(S32 loc); + + + ///////////////////////////// + // Accessors for data related to nearby speakers + + // MBW -- XXX -- Not sure how to get this data out of the TVC + BOOL getUsingPTT(const LLUUID& id); + 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. + + + ///////////////////////////// + // Recording controls + void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200); + void recordingLoopSave(const std::string& filename); + void recordingStop(); + + // Playback controls + void filePlaybackStart(const std::string& filename); + void filePlaybackStop(); + void filePlaybackSetPaused(bool paused); + void filePlaybackSetMode(bool vox = false, float speed = 1.0f); + + participantStatePtr_t findParticipantByID(const LLUUID& id); + + +#if 0 + //////////////////////////////////////// + // voice sessions. + typedef std::set<sessionStatePtr_t> sessionSet; + + typedef sessionSet::iterator sessionIterator; + sessionIterator sessionsBegin(void); + sessionIterator sessionsEnd(void); +#endif + + sessionStatePtr_t findSession(const std::string &handle); + sessionStatePtr_t findSessionBeingCreatedByURI(const std::string &uri); + sessionStatePtr_t findSession(const LLUUID &participant_id); + + sessionStatePtr_t addSession(const std::string &uri, const std::string &handle = std::string()); + void clearSessionHandle(const sessionStatePtr_t &session); + void setSessionHandle(const sessionStatePtr_t &session, const std::string &handle); + void setSessionURI(const sessionStatePtr_t &session, const std::string &uri); + void deleteSession(const sessionStatePtr_t &session); + void deleteAllSessions(void); + + void verifySessionState(void); + + void joinedAudioSession(const sessionStatePtr_t &session); + void leftAudioSession(const sessionStatePtr_t &session); + + // This is called in several places where the session _may_ need to be deleted. + // It contains logic for whether to delete the session or keep it around. + void reapSession(const sessionStatePtr_t &session); + + // Returns true if the session seems to indicate we've moved to a region on a different voice server + bool sessionNeedsRelog(const sessionStatePtr_t &session); + + + ////////////////////////////////////// + // buddy list stuff, needed for SLIM later + struct buddyListEntry + { + buddyListEntry(const std::string &uri); + std::string mURI; + std::string mDisplayName; + LLUUID mUUID; + bool mOnlineSL; + bool mOnlineSLim; + bool mCanSeeMeOnline; + bool mHasBlockListEntry; + bool mHasAutoAcceptListEntry; + bool mNameResolved; + bool mInSLFriends; + bool mInWebRTCBuddies; + }; + + typedef std::map<std::string, buddyListEntry*> buddyListMap; + + ///////////////////////////// + // session control messages + + void accountListBlockRulesSendMessage(); + void accountListAutoAcceptRulesSendMessage(); + + void sessionGroupCreateSendMessage(); + void sessionCreateSendMessage(const sessionStatePtr_t &session, bool startAudio = true, bool startText = false); + void sessionGroupAddSessionSendMessage(const sessionStatePtr_t &session, bool startAudio = true, bool startText = false); + void sessionMediaConnectSendMessage(const sessionStatePtr_t &session); // just joins the audio session + void sessionTextConnectSendMessage(const sessionStatePtr_t &session); // just joins the text session + void sessionTerminateSendMessage(const sessionStatePtr_t &session); + void sessionGroupTerminateSendMessage(const sessionStatePtr_t &session); + void sessionMediaDisconnectSendMessage(const sessionStatePtr_t &session); + // void sessionTextDisconnectSendMessage(sessionState *session); + + + + // Pokes the state machine to leave the audio session next time around. + void sessionTerminate(); + + // Pokes the state machine to shut down the connector and restart it. + void requestRelog(); + + // Does the actual work to get out of the audio session + void leaveAudioSession(); + + friend class LLWebRTCVoiceClientCapResponder; + + + void lookupName(const LLUUID &id); + void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); + void avatarNameResolved(const LLUUID &id, const std::string &name); + static void predAvatarNameResolution(const LLWebRTCVoiceClient::sessionStatePtr_t &session, LLUUID id, std::string name); + + boost::signals2::connection mAvatarNameCacheConnection; + + ///////////////////////////// + // Voice fonts + + void addVoiceFont(const S32 id, + const std::string &name, + const std::string &description, + const LLDate &expiration_date, + bool has_expired, + const S32 font_type, + const S32 font_status, + const bool template_font = false); + void accountGetSessionFontsResponse(int statusCode, const std::string &statusString); + void accountGetTemplateFontsResponse(int statusCode, const std::string &statusString); + +private: + + LLVoiceVersionInfo mVoiceVersion; + + // Coroutine support methods + //--- + void voiceControlCoro(); + void voiceControlStateMachine(); + int mVoiceControlState; + + bool endAndDisconnectSession(); + + bool callbackEndDaemon(const LLSD& data); + bool provisionVoiceAccount(); + void OnVoiceAccountProvisioned(const LLSD& body); + void OnVoiceAccountProvisionFailure(std::string url, int retries, LLSD body, const LLSD& result); + bool establishVoiceConnection(); + bool breakVoiceConnection(bool wait); + bool loginToWebRTC(); + void logoutOfWebRTC(bool wait); + + bool requestParcelVoiceInfo(); + + bool addAndJoinSession(const sessionStatePtr_t &nextSession); + bool terminateAudioSession(bool wait); + + bool waitForChannel(); + bool runSession(const sessionStatePtr_t &session); + + void recordingAndPlaybackMode(); + int voiceRecordBuffer(); + int voicePlaybackBuffer(); + + bool performMicTuning(); + //--- + /// Clean up objects created during a voice session. + void cleanUp(); + + bool mSessionTerminateRequested; + bool mRelogRequested; + // Number of times (in a row) "stateJoiningSession" case for spatial channel is reached in stateMachine(). + // The larger it is the greater is possibility there is a problem with connection to voice server. + // Introduced while fixing EXT-4313. + int mSpatialJoiningNum; + + static void idle(void *user_data); + + LLHost mDaemonHost; + LLSocket::ptr_t mSocket; + + // We should kill the voice daemon in case of connection alert + bool mTerminateDaemon; + + friend class LLWebRTCProtocolParser; + + std::string mAccountName; + std::string mAccountPassword; + std::string mChannelSDP; + std::string mRemoteChannelSDP; + std::string mAccountDisplayName; + + + bool mTuningMode; + float mTuningEnergy; + std::string mTuningAudioFile; + int mTuningMicVolume; + bool mTuningMicVolumeDirty; + int mTuningSpeakerVolume; + bool mTuningSpeakerVolumeDirty; + bool mDevicesListUpdated; // set to true when the device list has been updated + // and false when the panelvoicedevicesettings has queried for an update status. + + std::string mSpatialSessionURI; + std::string mSpatialSessionCredentials; + + std::string mMainSessionGroupHandle; // handle of the "main" session group. + + std::string mChannelName; // Name of the channel to be looked up + bool mAreaVoiceDisabled; + sessionStatePtr_t mAudioSession; // Session state for the current audio session + bool mAudioSessionChanged; // set to true when the above pointer gets changed, so observers can be notified. + + sessionStatePtr_t mNextAudioSession; // Session state for the audio session we're trying to join + + S32 mCurrentParcelLocalID; // Used to detect parcel boundary crossings + std::string mCurrentRegionName; // Used to detect parcel boundary crossings + + bool mConnectorEstablished; // set by "Create Connector" response + bool mAccountLoggedIn; // set by login message + int mNumberOfAliases; + U32 mCommandCookie; + + int mLoginRetryCount; + + sessionMap mSessionsByHandle; // Active sessions, indexed by session handle. Sessions which are being initiated may not be in this map. +#if 0 + sessionSet mSessions; // All sessions, not indexed. This is the canonical session list. +#endif + + bool mBuddyListMapPopulated; + bool mBlockRulesListReceived; + bool mAutoAcceptRulesListReceived; + buddyListMap mBuddyListMap; + + llwebrtc::LLWebRTCDeviceInterface *mWebRTCDeviceInterface; + llwebrtc::LLWebRTCSignalInterface *mWebRTCSignalingInterface; + llwebrtc::LLWebRTCAudioInterface *mWebRTCAudioInterface; + + LLVoiceDeviceList mCaptureDevices; + LLVoiceDeviceList mRenderDevices; + std::vector<llwebrtc::LLWebRTCIceCandidate> mIceCandidates; + bool mIceCompleted; + + bool mIsInitialized; + bool mShutdownComplete; + + bool checkParcelChanged(bool update = false); + bool switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = ""); + void joinSession(const sessionStatePtr_t &session); + + std::string nameFromAvatar(LLVOAvatar *avatar); + std::string nameFromID(const LLUUID &id); + bool IDFromName(const std::string name, LLUUID &uuid); + std::string displayNameFromAvatar(LLVOAvatar *avatar); + + + bool inSpatialChannel(void); + std::string getAudioSessionURI(); + std::string getAudioSessionHandle(); + + void setHidden(bool hidden); //virtual + void sendPositionAndVolumeUpdate(void); + + void sendFriendsListUpdates(); + +#if 0 + // start a text IM session with the specified user + // This will be asynchronous, the session may be established at a future time. + sessionStatePtr_t startUserIMSession(const LLUUID& uuid); +#endif + + void enforceTether(void); + + bool mSpatialCoordsDirty; + + LLVector3d mCameraPosition; + LLVector3d mCameraRequestedPosition; + LLVector3 mCameraVelocity; + LLMatrix3 mCameraRot; + + LLVector3d mAvatarPosition; + LLVector3 mAvatarVelocity; + LLQuaternion mAvatarRot; + + bool mMuteMic; + bool mMuteMicDirty; + bool mHidden; //Set to true during teleport to hide the agent's position. + + // Set to true when the friends list is known to have changed. + bool mFriendsListDirty; + + 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; + + BOOL mLipSyncEnabled; + + typedef std::set<LLVoiceClientParticipantObserver*> observer_set_t; + observer_set_t mParticipantObservers; + + void notifyParticipantObservers(); + + typedef std::set<LLVoiceClientStatusObserver*> status_observer_set_t; + status_observer_set_t mStatusObservers; + + void notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status); + + typedef std::set<LLFriendObserver*> friend_observer_set_t; + friend_observer_set_t mFriendObservers; + void notifyFriendObservers(); + + // Voice Fonts + + void expireVoiceFonts(); + void deleteVoiceFont(const LLUUID& id); + void deleteAllVoiceFonts(); + void deleteVoiceFontTemplates(); + + S32 getVoiceFontIndex(const LLUUID& id) const; + S32 getVoiceFontTemplateIndex(const LLUUID& id) const; + + void accountGetSessionFontsSendMessage(); + void accountGetTemplateFontsSendMessage(); + void sessionSetVoiceFontSendMessage(const sessionStatePtr_t &session); + + void updateVoiceMorphingMenu(); + void notifyVoiceFontObservers(); + + typedef enum e_voice_font_type + { + VOICE_FONT_TYPE_NONE = 0, + VOICE_FONT_TYPE_ROOT = 1, + VOICE_FONT_TYPE_USER = 2, + VOICE_FONT_TYPE_UNKNOWN + } EVoiceFontType; + + typedef enum e_voice_font_status + { + VOICE_FONT_STATUS_NONE = 0, + VOICE_FONT_STATUS_FREE = 1, + VOICE_FONT_STATUS_NOT_FREE = 2, + VOICE_FONT_STATUS_UNKNOWN + } EVoiceFontStatus; + + struct voiceFontEntry + { + voiceFontEntry(LLUUID& id); + ~voiceFontEntry(); + + LLUUID mID; + S32 mFontIndex; + std::string mName; + LLDate mExpirationDate; + S32 mFontType; + S32 mFontStatus; + bool mIsNew; + + LLFrameTimer mExpiryTimer; + LLFrameTimer mExpiryWarningTimer; + }; + + bool mVoiceFontsReceived; + bool mVoiceFontsNew; + bool mVoiceFontListDirty; + voice_effect_list_t mVoiceFontList; + voice_effect_list_t mVoiceFontTemplateList; + + typedef std::map<const LLUUID, voiceFontEntry*> voice_font_map_t; + voice_font_map_t mVoiceFontMap; + voice_font_map_t mVoiceFontTemplateMap; + + typedef std::set<LLVoiceEffectObserver*> voice_font_observer_set_t; + voice_font_observer_set_t mVoiceFontObservers; + + LLFrameTimer mVoiceFontExpiryTimer; + + + // Audio capture buffer + + void captureBufferRecordStartSendMessage(); + void captureBufferRecordStopSendMessage(); + void captureBufferPlayStartSendMessage(const LLUUID& voice_font_id = LLUUID::null); + void captureBufferPlayStopSendMessage(); + + bool mCaptureBufferMode; // Disconnected from voice channels while using the capture buffer. + bool mCaptureBufferRecording; // A voice sample is being captured. + bool mCaptureBufferRecorded; // A voice sample is captured in the buffer ready to play. + bool mCaptureBufferPlaying; // A voice sample is being played. + + LLTimer mCaptureTimer; + LLUUID mPreviewVoiceFont; + LLUUID mPreviewVoiceFontLast; + S32 mPlayRequestCount; + bool mIsInTuningMode; + bool mIsInChannel; + bool mIsJoiningSession; + bool mIsWaitingForFonts; + bool mIsLoggingIn; + bool mIsLoggedIn; + bool mIsProcessingChannels; + bool mIsCoroutineActive; + + // This variables can last longer than WebRTC in coroutines so we need them as static + static bool sShuttingDown; + static bool sConnected; + static LLPumpIO* sPump; + + LLEventMailDrop mWebRTCPump; +}; + + +/** + * @class LLWebRTCProtocolParser + * @brief This class helps construct new LLIOPipe specializations + * @see LLIOPipe + * + * THOROUGH_DESCRIPTION + */ +class LLWebRTCProtocolParser : public LLIOPipe +{ + LOG_CLASS(LLWebRTCProtocolParser); +public: + LLWebRTCProtocolParser(); + virtual ~LLWebRTCProtocolParser(); + +protected: + /* @name LLIOPipe virtual implementations + */ + //@{ + /** + * @brief Process the data in buffer + */ + virtual EStatus process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump); + //@} + + std::string mInput; + + // Expat control members + XML_Parser parser; + int responseDepth; + bool ignoringTags; + bool isEvent; + int ignoreDepth; + + // Members for processing responses. The values are transient and only valid within a call to processResponse(). + int returnCode; + int statusCode; + std::string statusString; + std::string requestId; + std::string actionString; + std::string connectorHandle; + std::string versionID; + std::string mBuildID; + std::string accountHandle; + std::string sessionHandle; + std::string sessionGroupHandle; + std::string alias; + std::string applicationString; + + // Members for processing events. The values are transient and only valid within a call to processResponse(). + std::string eventTypeString; + int state; + std::string uriString; + bool isChannel; + bool incoming; + bool enabled; + std::string nameString; + std::string audioMediaString; + std::string deviceString; + std::string displayNameString; + int participantType; + bool isLocallyMuted; + bool isModeratorMuted; + bool isSpeaking; + int volume; + F32 energy; + std::string messageHeader; + std::string messageBody; + std::string notificationType; + bool hasText; + bool hasAudio; + bool hasVideo; + bool terminated; + std::string blockMask; + std::string presenceOnly; + std::string autoAcceptMask; + std::string autoAddAsBuddy; + int numberOfAliases; + std::string subscriptionHandle; + std::string subscriptionType; + S32 id; + std::string descriptionString; + LLDate expirationDate; + bool hasExpired; + S32 fontType; + S32 fontStatus; + std::string mediaCompletionType; + + // Members for processing text between tags + std::string textBuffer; + bool accumulateText; + + void reset(); + + void processResponse(std::string tag); + + static void XMLCALL ExpatStartTag(void *data, const char *el, const char **attr); + static void XMLCALL ExpatEndTag(void *data, const char *el); + static void XMLCALL ExpatCharHandler(void *data, const XML_Char *s, int len); + + void StartTag(const char *tag, const char **attr); + void EndTag(const char *tag); + void CharData(const char *buffer, int length); + LLDate expiryTimeStampToLLDate(const std::string& WebRTC_ts); + +}; + +class LLWebRTCSecurity : public LLSingleton<LLWebRTCSecurity> +{ + LLSINGLETON(LLWebRTCSecurity); + virtual ~LLWebRTCSecurity(); + + public: + std::string connectorHandle() { return mConnectorHandle; }; + std::string accountHandle() { return mAccountHandle; }; + + private: + std::string mConnectorHandle; + std::string mAccountHandle; +}; + +class LLVoiceWebRTCStats : public LLSingleton<LLVoiceWebRTCStats> +{ + LLSINGLETON(LLVoiceWebRTCStats); + LOG_CLASS(LLVoiceWebRTCStats); + virtual ~LLVoiceWebRTCStats(); + + private: + F64SecondsImplicit mStartTime; + + U32 mConnectCycles; + + F64 mConnectTime; + U32 mConnectAttempts; + + F64 mProvisionTime; + U32 mProvisionAttempts; + + F64 mEstablishTime; + U32 mEstablishAttempts; + + public: + + void reset(); + void connectionAttemptStart(); + void connectionAttemptEnd(bool success); + void provisionAttemptStart(); + void provisionAttemptEnd(bool success); + void establishAttemptStart(); + void establishAttemptEnd(bool success); + LLSD read(); +}; + +#endif //LL_WebRTC_VOICE_CLIENT_H + |