From 0e6103e3a943c7f7726a93535048c634eb85eefc Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Thu, 25 Jan 2024 20:53:19 -0800 Subject: Checkpoint Ad-Hoc voice. Unlike vivox, P2P uses the ad-hoc voice mechanism, which is also used by group voice. --- indra/newview/llimview.cpp | 8 +- indra/newview/llvoicechannel.cpp | 1 + indra/newview/llvoiceclient.cpp | 7 + indra/newview/llvoiceclient.h | 2 + indra/newview/llvoicewebrtc.cpp | 693 ++++++++++++++++++++++----------------- indra/newview/llvoicewebrtc.h | 229 +++++++------ 6 files changed, 513 insertions(+), 427 deletions(-) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 61a01d7418..3e03dbef8f 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -665,8 +665,11 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& // set P2P type by default mSessionType = P2P_SESSION; - if (IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType) + if ((IM_NOTHING_SPECIAL == mType || IM_SESSION_P2P_INVITE == mType) && LLVoiceClient::getInstance()->hasP2PInterface()) { + // only use LLVoiceChannelP2P if the provider can handle the special P2P interface, + // which uses the voice server to relay calls and invites. Otherwise, + // we use the group voice provider. mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); } else @@ -2034,7 +2037,8 @@ bool LLIMModel::sendStartSession( return true; } - else if ( dialog == IM_SESSION_CONFERENCE_START ) + else if (( dialog == IM_SESSION_CONFERENCE_START ) || + (((dialog == IM_SESSION_P2P_INVITE) || (dialog == IM_NOTHING_SPECIAL)) && !LLVoiceClient::getInstance()->hasP2PInterface())) { LLSD agents; for (int i = 0; i < (S32) ids.size(); i++) diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index b0eb8d962c..afac9ed6f8 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -654,6 +654,7 @@ void LLVoiceChannelGroup::voiceCallCapCoro(std::string url) LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got " << iter->first << LL_ENDL; } + LL_INFOS("Voice") << "LLVoiceCallCapResponder::result got " << result << LL_ENDL; channelp->setChannelInfo( result["voice_credentials"]["channel_uri"].asString(), diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 294ae0c9ad..54840a1235 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -486,6 +486,13 @@ std::string LLVoiceClient::getCurrentChannel() //--------------------------------------- // invitations +bool LLVoiceClient::hasP2PInterface() +{ + if (mVoiceModule) + return mVoiceModule->hasP2PInterface(); + return false; +} + void LLVoiceClient::callUser(const LLUUID &uuid) { if (mVoiceModule) mVoiceModule->callUser(uuid); diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 1e8ff21b4b..1a20de6109 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -186,6 +186,7 @@ public: /// @name invitations //@{ // start a voice channel with the specified user + virtual bool hasP2PInterface()=0; virtual void callUser(const LLUUID &uuid)=0; virtual bool isValidChannel(std::string& channelHandle)=0; virtual bool answerInvite(std::string &channelHandle)=0; @@ -382,6 +383,7 @@ public: // NOTE that it will return an empty string if it's in the process of joining a channel. std::string getCurrentChannel(); // start a voice channel with the specified user + bool hasP2PInterface(); // true - can use the following. false - use conference/ad-hoc instead void callUser(const LLUUID &uuid); bool isValidChannel(std::string& channelHandle); bool answerInvite(std::string &channelHandle); diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index c9180b7e99..fcdd818757 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -419,15 +419,27 @@ void LLWebRTCVoiceClient::OnConnectionEstablished(const std::string& channelID, } mSession = mNextSession; mNextSession.reset(); - LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN); } - else if (mSession && mSession->mChannelID == channelID) + + if (mSession && mSession->mChannelID == channelID) { + LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED); LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN); } } } +void LLWebRTCVoiceClient::OnConnectionShutDown(const std::string &channelID, const LLUUID ®ionID) +{ + if (gAgent.getRegion()->getRegionID() == regionID) + { + if (mSession && mSession->mChannelID == channelID) + { + LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL); + } + } +} + void LLWebRTCVoiceClient::idle(void* user_data) { } @@ -492,8 +504,12 @@ LLWebRTCVoiceClient::parcelSessionState::parcelSessionState(const std::string &c mWebRTCConnections.emplace_back(new LLVoiceWebRTCSpatialConnection(region_id, parcel_local_id, channelID)); } -LLWebRTCVoiceClient::adhocSessionState::adhocSessionState(const std::string &channelID) +LLWebRTCVoiceClient::adhocSessionState::adhocSessionState(const std::string &channelID, const std::string& credentials) : + mCredentials(credentials) { + LLUUID region_id = gAgent.getRegion()->getRegionID(); + mChannelID = channelID; + mWebRTCConnections.emplace_back(new LLVoiceWebRTCAdHocConnection(region_id, channelID, credentials)); } bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates() @@ -1112,7 +1128,6 @@ bool LLWebRTCVoiceClient::isParticipant(const LLUUID &speaker_id) return false; } - LLWebRTCVoiceClient::participantStatePtr_t LLWebRTCVoiceClient::sessionState::findParticipant(const std::string &uri) { participantStatePtr_t result; @@ -1192,10 +1207,10 @@ bool LLWebRTCVoiceClient::startParcelSession(const std::string &channelID, S32 p return true; } -bool LLWebRTCVoiceClient::startAdHocSession(const std::string &channelID) +bool LLWebRTCVoiceClient::startAdHocSession(const std::string &channelID, const std::string &credentials) { leaveChannel(false); - mNextSession = addSession(channelID, sessionState::ptr_t(new adhocSessionState(channelID))); + mNextSession = addSession(channelID, sessionState::ptr_t(new adhocSessionState(channelID, credentials))); return true; } @@ -1211,9 +1226,8 @@ void LLWebRTCVoiceClient::joinSession(const sessionStatePtr_t &session) } } -void LLWebRTCVoiceClient::callUser(const LLUUID &uuid) -{ - startAdHocSession(uuid.asString()); +void LLWebRTCVoiceClient::callUser(const LLUUID &uuid) +{ } void LLWebRTCVoiceClient::endUserIMSession(const LLUUID &uuid) @@ -1226,16 +1240,7 @@ bool LLWebRTCVoiceClient::isValidChannel(std::string &channelID) } bool LLWebRTCVoiceClient::answerInvite(std::string &channelID) -{ - // this is only ever used to answer incoming p2p call invites. - - sessionStatePtr_t session(findP2PSession(LLUUID(channelID))); - if(session) - { - startAdHocSession(channelID); - return true; - } - +{ return false; } @@ -1419,7 +1424,11 @@ bool LLWebRTCVoiceClient::inSpatialChannel() { bool result = true; - if(mSession) + if (mNextSession) + { + result = mNextSession->isSpatial(); + } + else if(mSession) { result = mSession->isSpatial(); } @@ -2299,77 +2308,25 @@ std::string LLWebRTCVoiceClient::sipURIFromID(const LLUUID& id) { return id.asSt ///////////////////////////// // LLVoiceWebRTCConnection -LLVoiceWebRTCConnection::LLVoiceWebRTCConnection() : - mWebRTCAudioInterface(nullptr), - mWebRTCPeerConnection(nullptr), - mMuted(true), - mSpeakerVolume(0.0), - mMicGain(0.0) -{ - -} - -LLVoiceWebRTCConnection::~LLVoiceWebRTCConnection() -{ - if (LLWebRTCVoiceClient::isShuttingDown()) - { - // peer connection and observers will be cleaned up - // by llwebrtc::terminate() on shutdown. - return; - } - llwebrtc::freePeerConnection(mWebRTCPeerConnection); - mWebRTCPeerConnection = nullptr; -} - - -void LLVoiceWebRTCConnection::setMuteMic(bool muted) -{ - mMuted = muted; - if (mWebRTCAudioInterface) - { - mWebRTCAudioInterface->setMute(muted); - } -} - -void LLVoiceWebRTCConnection::setMicGain(F32 gain) -{ - mMicGain = gain; - if (mWebRTCAudioInterface) - { - mWebRTCAudioInterface->setSendVolume(gain); - } -} - -void LLVoiceWebRTCConnection::setSpeakerVolume(F32 volume) -{ - mSpeakerVolume = volume; - if (mWebRTCAudioInterface) - { - mWebRTCAudioInterface->setReceiveVolume(volume); - } -} - -///////////////////////////// -// WebRTC Signaling Handlers - -LLVoiceWebRTCSpatialConnection::LLVoiceWebRTCSpatialConnection(const LLUUID ®ionID, S32 parcelLocalID, const std::string &channelID) : - mWebRTCPeerConnection(nullptr), +LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID ®ionID, const std::string &channelID) : mWebRTCAudioInterface(nullptr), mWebRTCDataInterface(nullptr), - mIceCompleted(false), - mTrickling(false), mVoiceConnectionState(VOICE_STATE_START_SESSION), - mChannelID(channelID), - mRegionID(regionID), - mParcelLocalID(parcelLocalID), + mMuted(true), mShutDown(false), - mOutstandingRequests(0) + mTrickling(false), + mIceCompleted(false), + mSpeakerVolume(0.0), + mMicGain(0.0), + mOutstandingRequests(0), + mChannelID(channelID), + mRegionID(regionID) { mWebRTCPeerConnection = llwebrtc::newPeerConnection(); mWebRTCPeerConnection->setSignalingObserver(this); } -LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection() +LLVoiceWebRTCConnection::~LLVoiceWebRTCConnection() { if (LLWebRTCVoiceClient::isShuttingDown()) { @@ -2377,11 +2334,11 @@ LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection() // by llwebrtc::terminate() on shutdown. return; } - assert(mOutstandingRequests == 0); - mWebRTCPeerConnection->unsetSignalingObserver(this); + llwebrtc::freePeerConnection(mWebRTCPeerConnection); + mWebRTCPeerConnection = nullptr; } -void LLVoiceWebRTCSpatialConnection::OnIceGatheringState(llwebrtc::LLWebRTCSignalingObserver::IceGatheringState state) +void LLVoiceWebRTCConnection::OnIceGatheringState(llwebrtc::LLWebRTCSignalingObserver::IceGatheringState state) { LL_INFOS("Voice") << "Ice Gathering voice account. " << state << LL_ENDL; @@ -2403,13 +2360,13 @@ void LLVoiceWebRTCSpatialConnection::OnIceGatheringState(llwebrtc::LLWebRTCSigna } } -void LLVoiceWebRTCSpatialConnection::OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate &candidate) +void LLVoiceWebRTCConnection::OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate &candidate) { LLMutexLock lock(&mVoiceStateMutex); mIceCandidates.push_back(candidate); } -void LLVoiceWebRTCSpatialConnection::onIceUpdateComplete(bool ice_completed, const LLSD &result) +void LLVoiceWebRTCConnection::onIceUpdateComplete(bool ice_completed, const LLSD &result) { if (LLWebRTCVoiceClient::isShuttingDown()) { @@ -2419,7 +2376,7 @@ void LLVoiceWebRTCSpatialConnection::onIceUpdateComplete(bool ice_completed, con mOutstandingRequests--; } -void LLVoiceWebRTCSpatialConnection::onIceUpdateError(int retries, std::string url, LLSD body, bool ice_completed, const LLSD &result) +void LLVoiceWebRTCConnection::onIceUpdateError(int retries, std::string url, LLSD body, bool ice_completed, const LLSD &result) { if (LLWebRTCVoiceClient::isShuttingDown()) { @@ -2435,8 +2392,8 @@ void LLVoiceWebRTCSpatialConnection::onIceUpdateError(int retries, std::string u url, LLCore::HttpRequest::DEFAULT_POLICY_ID, body, - boost::bind(&LLVoiceWebRTCSpatialConnection::onIceUpdateComplete, this, ice_completed, _1), - boost::bind(&LLVoiceWebRTCSpatialConnection::onIceUpdateError, this, retries - 1, url, body, ice_completed, _1)); + boost::bind(&LLVoiceWebRTCConnection::onIceUpdateComplete, this, ice_completed, _1), + boost::bind(&LLVoiceWebRTCConnection::onIceUpdateError, this, retries - 1, url, body, ice_completed, _1)); return; } @@ -2450,7 +2407,7 @@ void LLVoiceWebRTCSpatialConnection::onIceUpdateError(int retries, std::string u mOutstandingRequests--; } -void LLVoiceWebRTCSpatialConnection::OnOfferAvailable(const std::string &sdp) +void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp) { LL_INFOS("Voice") << "On Offer Available." << LL_ENDL; LLMutexLock lock(&mVoiceStateMutex); @@ -2461,110 +2418,14 @@ void LLVoiceWebRTCSpatialConnection::OnOfferAvailable(const std::string &sdp) } } -void LLVoiceWebRTCSpatialConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface *audio_interface) +void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface *audio_interface) { LL_INFOS("Voice") << "On AudioEstablished." << LL_ENDL; mWebRTCAudioInterface = audio_interface; setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED); } -void LLVoiceWebRTCSpatialConnection::OnDataReceived(const std::string &data, bool binary) -{ - // incoming data will be a json structure (if it's not binary.) We may pack - // binary for size reasons. Most of the keys in the json objects are - // single or double characters for size reasons. - // The primary element is: - // An object where each key is an agent id. (in the future, we may allow - // integer indices into an agentid list, populated on join commands. For size. - // Each key will point to a json object with keys identifying what's updated. - // 'p' - audio source power (level/volume) (int8 as int) - // 'j' - join - object of join data (TBD) (true for now) - // 'l' - boolean, always true if exists. - - if (binary) - { - LL_WARNS("Voice") << "Binary data received from data channel." << LL_ENDL; - return; - } - - Json::Reader reader; - Json::Value voice_data; - if (reader.parse(data, voice_data, false)) // don't collect comments - { - if (!voice_data.isObject()) - { - LL_WARNS("Voice") << "Expected object from data channel:" << data << LL_ENDL; - return; - } - bool new_participant = false; - for (auto &participant_id : voice_data.getMemberNames()) - { - LLUUID agent_id(participant_id); - if (agent_id.isNull()) - { - LL_WARNS("Voice") << "Bad participant ID from data channel (" << participant_id << "):" << data << LL_ENDL; - continue; - } - - LLWebRTCVoiceClient::participantStatePtr_t participant = LLWebRTCVoiceClient::getInstance()->findParticipantByID(mChannelID, agent_id); - bool joined = false; - bool primary = false; - if (voice_data[participant_id].isMember("j")) - { - joined = true; - primary = voice_data[participant_id]["j"].get("p", Json::Value(false)).asBool(); - } - - new_participant |= joined; - if (!participant && joined && primary) - { - participant = LLWebRTCVoiceClient::getInstance()->addParticipantByID(mChannelID, agent_id); - } - if (participant) - { - if (voice_data[participant_id].get("l", Json::Value(false)).asBool()) - { - if (agent_id != gAgentID) - { - LLWebRTCVoiceClient::getInstance()->removeParticipantByID(mChannelID, agent_id); - } - } - else - { - F32 level = (F32) (voice_data[participant_id].get("p", Json::Value(participant->mLevel)).asInt()) / 128; - // convert to decibles - participant->mLevel = level; - /* WebRTC appears to have deprecated VAD, but it's still in the Audio Processing Module so maybe we - can use it at some point when we actually process frames. */ - participant->mIsSpeaking = participant->mLevel > SPEAKING_AUDIO_LEVEL; - } - } - } - } -} - -void LLVoiceWebRTCSpatialConnection::OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface) -{ - if (data_interface) - { - mWebRTCDataInterface = data_interface; - mWebRTCDataInterface->setDataObserver(this); - - Json::FastWriter writer; - Json::Value root = Json::objectValue; - Json::Value join_obj = Json::objectValue; - LLUUID regionID = gAgent.getRegion()->getRegionID(); - if (regionID == mRegionID) - { - join_obj["p"] = true; - } - root["j"] = join_obj; - std::string json_data = writer.write(root); - mWebRTCDataInterface->sendData(json_data, false); - } -} - -void LLVoiceWebRTCSpatialConnection::OnRenegotiationNeeded() +void LLVoiceWebRTCConnection::OnRenegotiationNeeded() { LL_INFOS("Voice") << "On Renegotiation Needed." << LL_ENDL; if (!mShutDown) @@ -2573,13 +2434,13 @@ void LLVoiceWebRTCSpatialConnection::OnRenegotiationNeeded() } } -void LLVoiceWebRTCSpatialConnection::OnPeerShutDown() +void LLVoiceWebRTCConnection::OnPeerShutDown() { setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); mOutstandingRequests--; } -void LLVoiceWebRTCSpatialConnection::processIceUpdates() +void LLVoiceWebRTCConnection::processIceUpdates() { if (mShutDown || LLWebRTCVoiceClient::isShuttingDown()) { @@ -2596,39 +2457,40 @@ void LLVoiceWebRTCSpatialConnection::processIceUpdates() LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); if (!regionp || !regionp->capabilitiesReceived()) { - LL_DEBUGS("Voice") << "no capabilities for ice gathering; waiting " << LL_ENDL; - return; + LL_DEBUGS("Voice") << "no capabilities for ice gathering; waiting " << LL_ENDL; + return; } std::string url = regionp->getCapability("VoiceSignalingRequest"); if (url.empty()) { - return; + return; } LL_DEBUGS("Voice") << "region ready to complete voice signaling; url=" << url << LL_ENDL; - if (!mIceCandidates.empty()) { - LLSD candidates = LLSD::emptyArray(); - for (auto &ice_candidate : mIceCandidates) - { + if (!mIceCandidates.empty()) + { + LLSD candidates = LLSD::emptyArray(); + for (auto &ice_candidate : mIceCandidates) + { LLSD body_candidate; body_candidate["sdpMid"] = ice_candidate.sdp_mid; body_candidate["sdpMLineIndex"] = ice_candidate.mline_index; body_candidate["candidate"] = ice_candidate.candidate; candidates.append(body_candidate); - } - body["candidates"] = candidates; - mIceCandidates.clear(); + } + body["candidates"] = candidates; + mIceCandidates.clear(); } else if (mIceCompleted) { - LLSD body_candidate; - body_candidate["completed"] = true; - body["candidate"] = body_candidate; - iceCompleted = mIceCompleted; - mIceCompleted = false; + LLSD body_candidate; + body_candidate["completed"] = true; + body["candidate"] = body_candidate; + iceCompleted = mIceCompleted; + mIceCompleted = false; } - + body["viewer_session"] = mViewerSession; LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); @@ -2649,14 +2511,56 @@ void LLVoiceWebRTCSpatialConnection::processIceUpdates() } } -bool LLVoiceWebRTCSpatialConnection::requestVoiceConnection() + +void LLVoiceWebRTCConnection::setMuteMic(bool muted) { - LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); + mMuted = muted; + if (mWebRTCAudioInterface) + { + mWebRTCAudioInterface->setMute(muted); + } +} - LL_INFOS("Voice") << "Requesting voice connection." << LL_ENDL; +void LLVoiceWebRTCConnection::setMicGain(F32 gain) +{ + mMicGain = gain; + if (mWebRTCAudioInterface) + { + mWebRTCAudioInterface->setSendVolume(gain); + } +} + +void LLVoiceWebRTCConnection::setSpeakerVolume(F32 volume) +{ + mSpeakerVolume = volume; + if (mWebRTCAudioInterface) + { + mWebRTCAudioInterface->setReceiveVolume(volume); + } +} + +void LLVoiceWebRTCConnection::sendData(const std::string &data) +{ + if (getVoiceConnectionState() == VOICE_STATE_SESSION_UP && mWebRTCDataInterface) + { + mWebRTCDataInterface->sendData(data, false); + } +} + +bool LLVoiceWebRTCConnection::breakVoiceConnection(bool corowait) +{ + LL_INFOS("Voice") << "Disconnecting voice." << LL_ENDL; + if (mWebRTCDataInterface) + { + mWebRTCDataInterface->unsetDataObserver(this); + mWebRTCDataInterface = nullptr; + } + mWebRTCAudioInterface = nullptr; + LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); if (!regionp || !regionp->capabilitiesReceived()) { LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL; + setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); return false; } @@ -2666,60 +2570,105 @@ bool LLVoiceWebRTCSpatialConnection::requestVoiceConnection() return false; } - LL_DEBUGS("Voice") << "region ready for voice provisioning; url=" << url << LL_ENDL; + LL_DEBUGS("Voice") << "region ready for voice break; url=" << url << 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); LLVoiceWebRTCStats::getInstance()->provisionAttemptStart(); LLSD body; - LLSD jsep; - jsep["type"] = "offer"; - { - LLMutexLock lock(&mVoiceStateMutex); - jsep["sdp"] = mChannelSDP; - } - body["jsep"] = jsep; - if (mParcelLocalID != INVALID_PARCEL_ID) - { - body["parcel_local_id"] = mParcelLocalID; - } + body["logout"] = TRUE; + body["viewer_session"] = mViewerSession; LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost( url, LLCore::HttpRequest::DEFAULT_POLICY_ID, body, - boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestSuccess, this, _1), - boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestFailure, this, url, 3, body, _1)); + boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestSuccess, this, _1), + boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestFailure, this, url, 3, body, _1)); + setVoiceConnectionState(VOICE_STATE_WAIT_FOR_EXIT); mOutstandingRequests++; return true; } -void LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestSuccess(const LLSD &result) +void LLVoiceWebRTCConnection::OnVoiceDisconnectionRequestSuccess(const LLSD &result) { if (LLWebRTCVoiceClient::isShuttingDown()) { return; } - LLVoiceWebRTCStats::getInstance()->provisionAttemptEnd(true); - if (result.has("viewer_session") && result.has("jsep") && result["jsep"].has("type") && result["jsep"]["type"] == "answer" && result["jsep"].has("sdp")) + if (mWebRTCPeerConnection) { - mRemoteChannelSDP = result["jsep"]["sdp"].asString(); - mViewerSession = result["viewer_session"]; + mOutstandingRequests++; + mWebRTCPeerConnection->shutdownConnection(); } else { - setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); - mOutstandingRequests--; - return; + setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); } + mOutstandingRequests--; +} - LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response" +void LLVoiceWebRTCConnection::OnVoiceDisconnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result) +{ + if (LLWebRTCVoiceClient::isShuttingDown()) + { + return; + } + if (retries >= 0) + { + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost( + url, + LLCore::HttpRequest::DEFAULT_POLICY_ID, + body, + boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestSuccess, this, _1), + boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestFailure, this, url, retries - 1, body, _1)); + return; + } + if (mWebRTCPeerConnection) + { + mOutstandingRequests++; + mWebRTCPeerConnection->shutdownConnection(); + } + else + { + setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); + } + mOutstandingRequests--; +} + + +void LLVoiceWebRTCConnection::OnVoiceConnectionRequestSuccess(const LLSD &result) +{ + if (LLWebRTCVoiceClient::isShuttingDown()) + { + return; + } + LLVoiceWebRTCStats::getInstance()->provisionAttemptEnd(true); + + if (result.has("viewer_session") && result.has("jsep") && result["jsep"].has("type") && result["jsep"]["type"] == "answer" && + result["jsep"].has("sdp")) + { + mRemoteChannelSDP = result["jsep"]["sdp"].asString(); + mViewerSession = result["viewer_session"]; + } + else + { + setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); + mOutstandingRequests--; + return; + } + + LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response" << " channel sdp " << mRemoteChannelSDP << LL_ENDL; mWebRTCPeerConnection->AnswerAvailable(mRemoteChannelSDP); mOutstandingRequests--; } -void LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result) +void LLVoiceWebRTCConnection::OnVoiceConnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result) { if (LLWebRTCVoiceClient::isShuttingDown()) { @@ -2731,17 +2680,17 @@ void LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestFailure(std::string url, LLCore::HttpRequest::DEFAULT_POLICY_ID, body, - boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestSuccess, this, _1), - boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestFailure, this, url, retries - 1, body, _1)); + boost::bind(&LLVoiceWebRTCConnection::OnVoiceConnectionRequestSuccess, this, _1), + boost::bind(&LLVoiceWebRTCConnection::OnVoiceConnectionRequestFailure, this, url, retries - 1, body, _1)); return; } LL_WARNS("Voice") << "Unable to connect voice." << body << " RESULT: " << result << LL_ENDL; - setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); + setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); mOutstandingRequests--; } -bool LLVoiceWebRTCSpatialConnection::connectionStateMachine() -{ +bool LLVoiceWebRTCConnection::connectionStateMachine() +{ processIceUpdates(); switch (getVoiceConnectionState()) @@ -2819,7 +2768,6 @@ bool LLVoiceWebRTCSpatialConnection::connectionStateMachine() LLWebRTCVoiceClient::getInstance()->OnConnectionFailure(mChannelID, mRegionID); setVoiceConnectionState(VOICE_STATE_DISCONNECT); break; - break; case VOICE_STATE_DISCONNECT: breakVoiceConnection(true); @@ -2831,13 +2779,17 @@ bool LLVoiceWebRTCSpatialConnection::connectionStateMachine() { { LLMutexLock lock(&mVoiceStateMutex); - if (!mShutDown) + if (!mShutDown) { mVoiceConnectionState = VOICE_STATE_START_SESSION; } else { - return mOutstandingRequests > 0; + if (mOutstandingRequests <= 0) + { + LLWebRTCVoiceClient::getInstance()->OnConnectionShutDown(mChannelID, mRegionID); + return false; + } } } break; @@ -2852,29 +2804,133 @@ bool LLVoiceWebRTCSpatialConnection::connectionStateMachine() return true; } +void LLVoiceWebRTCConnection::OnDataReceived(const std::string &data, bool binary) +{ + // incoming data will be a json structure (if it's not binary.) We may pack + // binary for size reasons. Most of the keys in the json objects are + // single or double characters for size reasons. + // The primary element is: + // An object where each key is an agent id. (in the future, we may allow + // integer indices into an agentid list, populated on join commands. For size. + // Each key will point to a json object with keys identifying what's updated. + // 'p' - audio source power (level/volume) (int8 as int) + // 'j' - join - object of join data (TBD) (true for now) + // 'l' - boolean, always true if exists. -void LLVoiceWebRTCSpatialConnection::sendData(const std::string& data) { - - if (getVoiceConnectionState() == VOICE_STATE_SESSION_UP && mWebRTCDataInterface) + if (binary) { - mWebRTCDataInterface->sendData(data, false); + LL_WARNS("Voice") << "Binary data received from data channel." << LL_ENDL; + return; + } + + Json::Reader reader; + Json::Value voice_data; + if (reader.parse(data, voice_data, false)) // don't collect comments + { + if (!voice_data.isObject()) + { + LL_WARNS("Voice") << "Expected object from data channel:" << data << LL_ENDL; + return; + } + bool new_participant = false; + for (auto &participant_id : voice_data.getMemberNames()) + { + LLUUID agent_id(participant_id); + if (agent_id.isNull()) + { + LL_WARNS("Voice") << "Bad participant ID from data channel (" << participant_id << "):" << data << LL_ENDL; + continue; + } + + LLWebRTCVoiceClient::participantStatePtr_t participant = + LLWebRTCVoiceClient::getInstance()->findParticipantByID(mChannelID, agent_id); + bool joined = false; + bool primary = false; + if (voice_data[participant_id].isMember("j")) + { + joined = true; + primary = voice_data[participant_id]["j"].get("p", Json::Value(false)).asBool(); + } + + new_participant |= joined; + if (!participant && joined && primary) + { + participant = LLWebRTCVoiceClient::getInstance()->addParticipantByID(mChannelID, agent_id); + } + if (participant) + { + if (voice_data[participant_id].get("l", Json::Value(false)).asBool()) + { + if (agent_id != gAgentID) + { + LLWebRTCVoiceClient::getInstance()->removeParticipantByID(mChannelID, agent_id); + } + } + else + { + F32 level = (F32) (voice_data[participant_id].get("p", Json::Value(participant->mLevel)).asInt()) / 128; + // convert to decibles + participant->mLevel = level; + /* WebRTC appears to have deprecated VAD, but it's still in the Audio Processing Module so maybe we + can use it at some point when we actually process frames. */ + participant->mIsSpeaking = participant->mLevel > SPEAKING_AUDIO_LEVEL; + } + } + } } } -bool LLVoiceWebRTCSpatialConnection::breakVoiceConnection(bool corowait) +void LLVoiceWebRTCConnection::OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface) { - LL_INFOS("Voice") << "Disconnecting voice." << LL_ENDL; - if (mWebRTCDataInterface) + if (data_interface) { - mWebRTCDataInterface->unsetDataObserver(this); - mWebRTCDataInterface = nullptr; + mWebRTCDataInterface = data_interface; + mWebRTCDataInterface->setDataObserver(this); + + Json::FastWriter writer; + Json::Value root = Json::objectValue; + Json::Value join_obj = Json::objectValue; + LLUUID regionID = gAgent.getRegion()->getRegionID(); + if (regionID == mRegionID) + { + join_obj["p"] = true; + } + root["j"] = join_obj; + std::string json_data = writer.write(root); + mWebRTCDataInterface->sendData(json_data, false); } - mWebRTCAudioInterface = nullptr; +} + +///////////////////////////// +// WebRTC Spatial Connection + +LLVoiceWebRTCSpatialConnection::LLVoiceWebRTCSpatialConnection(const LLUUID ®ionID, S32 parcelLocalID, const std::string &channelID) : + LLVoiceWebRTCConnection(regionID, channelID), + mParcelLocalID(parcelLocalID) +{ +} + +LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection() +{ + if (LLWebRTCVoiceClient::isShuttingDown()) + { + // peer connection and observers will be cleaned up + // by llwebrtc::terminate() on shutdown. + return; + } + assert(mOutstandingRequests == 0); + mWebRTCPeerConnection->unsetSignalingObserver(this); +} + + +bool LLVoiceWebRTCSpatialConnection::requestVoiceConnection() +{ LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); + + LL_INFOS("Voice") << "Requesting voice connection." << LL_ENDL; if (!regionp || !regionp->capabilitiesReceived()) { LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL; - setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); return false; } @@ -2884,89 +2940,110 @@ bool LLVoiceWebRTCSpatialConnection::breakVoiceConnection(bool corowait) return false; } - LL_DEBUGS("Voice") << "region ready for voice break; url=" << url << 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); + LL_DEBUGS("Voice") << "region ready for voice provisioning; url=" << url << LL_ENDL; LLVoiceWebRTCStats::getInstance()->provisionAttemptStart(); LLSD body; - body["logout"] = TRUE; - body["viewer_session"] = mViewerSession; + LLSD jsep; + jsep["type"] = "offer"; + { + LLMutexLock lock(&mVoiceStateMutex); + jsep["sdp"] = mChannelSDP; + } + body["jsep"] = jsep; + if (mParcelLocalID != INVALID_PARCEL_ID) + { + body["parcel_local_id"] = mParcelLocalID; + } LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost( url, LLCore::HttpRequest::DEFAULT_POLICY_ID, body, - boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestSuccess, this, _1), - boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestFailure, this, url, 3, body, _1)); - setVoiceConnectionState(VOICE_STATE_WAIT_FOR_EXIT); + boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestSuccess, this, _1), + boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceConnectionRequestFailure, this, url, 3, body, _1)); mOutstandingRequests++; return true; } -void LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestSuccess(const LLSD &result) +void LLVoiceWebRTCSpatialConnection::setMuteMic(bool muted) { - if (LLWebRTCVoiceClient::isShuttingDown()) + mMuted = muted; + if (mWebRTCAudioInterface) { - return; + LLViewerRegion *regionp = gAgent.getRegion(); + if (regionp && mRegionID == regionp->getRegionID()) + { + mWebRTCAudioInterface->setMute(muted); + } + else + { + // always mute to regions the agent isn't on, to prevent echo. + mWebRTCAudioInterface->setMute(true); + } } +} - if (mWebRTCPeerConnection) - { - mOutstandingRequests++; - mWebRTCPeerConnection->shutdownConnection(); - } - else - { - setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); - } - mOutstandingRequests--; +///////////////////////////// +// WebRTC Spatial Connection + +LLVoiceWebRTCAdHocConnection::LLVoiceWebRTCAdHocConnection(const LLUUID ®ionID, const std::string& channelID, const std::string& credentials) : + LLVoiceWebRTCConnection(regionID, channelID), + mCredentials(credentials) +{ } -void LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result) +LLVoiceWebRTCAdHocConnection::~LLVoiceWebRTCAdHocConnection() { if (LLWebRTCVoiceClient::isShuttingDown()) { + // peer connection and observers will be cleaned up + // by llwebrtc::terminate() on shutdown. return; } - if (retries >= 0) - { - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost( - url, - LLCore::HttpRequest::DEFAULT_POLICY_ID, - body, - boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestSuccess, this, _1), - boost::bind(&LLVoiceWebRTCSpatialConnection::OnVoiceDisconnectionRequestFailure, this, url, retries - 1, body, _1)); - return; - } - if (mWebRTCPeerConnection) + assert(mOutstandingRequests == 0); + mWebRTCPeerConnection->unsetSignalingObserver(this); +} + + +bool LLVoiceWebRTCAdHocConnection::requestVoiceConnection() +{ + LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); + + LL_INFOS("Voice") << "Requesting voice connection." << LL_ENDL; + if (!regionp || !regionp->capabilitiesReceived()) { - mOutstandingRequests++; - mWebRTCPeerConnection->shutdownConnection(); + LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL; + return false; } - else + + std::string url = regionp->getCapability("ProvisionVoiceAccountRequest"); + if (url.empty()) { - setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); + return false; } - mOutstandingRequests--; -} -void LLVoiceWebRTCSpatialConnection::setMuteMic(bool muted) -{ - mMuted = muted; - if (mWebRTCAudioInterface) + LL_DEBUGS("Voice") << "region ready for voice provisioning; url=" << url << LL_ENDL; + + LLVoiceWebRTCStats::getInstance()->provisionAttemptStart(); + LLSD body; + LLSD jsep; + jsep["type"] = "offer"; { - LLViewerRegion *regionp = gAgent.getRegion(); - if (regionp && mRegionID == regionp->getRegionID()) - { - mWebRTCAudioInterface->setMute(muted); - } - else - { - // always mute to regions the agent isn't on, to prevent echo. - mWebRTCAudioInterface->setMute(true); - } + LLMutexLock lock(&mVoiceStateMutex); + jsep["sdp"] = mChannelSDP; } + body["jsep"] = jsep; + body["credentials"] = mCredentials; + body["channel"] = mChannelID; + body["channel_type"] = "multiagent"; + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost( + url, + LLCore::HttpRequest::DEFAULT_POLICY_ID, + body, + boost::bind(&LLVoiceWebRTCAdHocConnection::OnVoiceConnectionRequestSuccess, this, _1), + boost::bind(&LLVoiceWebRTCAdHocConnection::OnVoiceConnectionRequestFailure, this, url, 3, body, _1)); + mOutstandingRequests++; + return true; } diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h index b2672ac108..f81c8c556e 100644 --- a/indra/newview/llvoicewebrtc.h +++ b/indra/newview/llvoicewebrtc.h @@ -144,10 +144,8 @@ public: // Note that gestures should only fire if this returns true. bool inProximalChannel() override; - void setNonSpatialChannel(const std::string& uri, - const std::string& credentials) override - { - + void setNonSpatialChannel(const std::string& uri, const std::string& credentials) override { + startAdHocSession(uri, credentials); } bool setSpatialChannel(const std::string &uri, const std::string &credentials) override @@ -172,6 +170,7 @@ public: /// @name invitations //@{ // start a voice channel with the specified user + bool hasP2PInterface() override { return false; } void callUser(const LLUUID &uuid) override; bool isValidChannel(std::string &channelID) override; bool answerInvite(std::string &channelID) override; @@ -247,6 +246,7 @@ public: void OnConnectionEstablished(const std::string& channelID, const LLUUID& regionID); + void OnConnectionShutDown(const std::string &channelID, const LLUUID ®ionID); void OnConnectionFailure(const std::string &channelID, const LLUUID& regionID); void sendPositionUpdate(bool force); void updateOwnVolume(); @@ -338,7 +338,7 @@ public: virtual bool processConnectionStates(); - void sendData(const std::string &data); + virtual void sendData(const std::string &data); void setMuteMic(bool muted); void setMicGain(F32 volume); @@ -427,11 +427,17 @@ public: class adhocSessionState : public sessionState { - public: - adhocSessionState(const std::string &channelID); + public: + adhocSessionState(const std::string &channelID, const std::string& credentials); bool isSpatial() override { return false; } bool isEstate() override { return false; } + + // don't send spatial data to adhoc sessions. + void sendData(const std::string &data) override { } + + protected: + std::string mCredentials; }; @@ -511,26 +517,6 @@ public: // It contains logic for whether to delete the session or keep it around. void reapSession(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 buddyListMap; - // Pokes the state machine to leave the audio session next time around. void sessionTerminate(); @@ -612,7 +598,6 @@ private: bool mBuddyListMapPopulated; bool mBlockRulesListReceived; bool mAutoAcceptRulesListReceived; - buddyListMap mBuddyListMap; llwebrtc::LLWebRTCDeviceInterface *mWebRTCDeviceInterface; @@ -624,8 +609,7 @@ private: bool startEstateSession(); bool startParcelSession(const std::string& channelID, S32 parcelID); - bool startAdHocSession(const std::string& channelID); - + bool startAdHocSession(const std::string& channelID, const std::string& credentials); void joinSession(const sessionStatePtr_t &session); @@ -749,147 +733,126 @@ class LLVoiceWebRTCStats : public LLSingleton LLSD read(); }; -class LLVoiceWebRTCConnection -{ - public: - LLVoiceWebRTCConnection(); - - virtual ~LLVoiceWebRTCConnection() = 0; - - virtual bool connectionStateMachine() = 0; - - virtual void sendData(const std::string &data) {}; - virtual void setMuteMic(bool muted); - virtual void setMicGain(F32 volume); - virtual void setSpeakerVolume(F32 volume); - - virtual void shutDown() = 0; - -protected: - - bool mMuted; - F32 mMicGain; - F32 mSpeakerVolume; - - llwebrtc::LLWebRTCPeerConnection *mWebRTCPeerConnection; - llwebrtc::LLWebRTCAudioInterface *mWebRTCAudioInterface; -}; - - -class LLVoiceWebRTCSpatialConnection : - public LLVoiceWebRTCConnection, - public llwebrtc::LLWebRTCSignalingObserver, +class LLVoiceWebRTCConnection : + public llwebrtc::LLWebRTCSignalingObserver, public llwebrtc::LLWebRTCDataObserver { public: - LLVoiceWebRTCSpatialConnection(const LLUUID ®ionID, S32 parcelLocalID, const std::string &channelID); + LLVoiceWebRTCConnection(const LLUUID ®ionID, const std::string &channelID); - virtual ~LLVoiceWebRTCSpatialConnection(); + virtual ~LLVoiceWebRTCConnection() = 0; ////////////////////////////// /// @name Signaling notification // LLWebRTCSignalingObserver //@{ - void OnIceGatheringState(IceGatheringState state) override; - void OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate &candidate) override; - void OnOfferAvailable(const std::string &sdp) override; - void OnRenegotiationNeeded() override; - void OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface *audio_interface) override; - void OnPeerShutDown() override; + virtual void OnIceGatheringState(IceGatheringState state); + virtual void OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate &candidate); + virtual void OnOfferAvailable(const std::string &sdp); + virtual void OnRenegotiationNeeded() override; + virtual void OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface *audio_interface); + virtual void OnPeerShutDown(); //@} ///////////////////////// /// @name Data Notification /// LLWebRTCDataObserver //@{ - void OnDataReceived(const std::string &data, bool binary) override; - void OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface) override; + virtual void OnDataReceived(const std::string &data, bool binary); + virtual void OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface); //@} - void processIceUpdates(); - void onIceUpdateComplete(bool ice_completed, const LLSD &result); - void onIceUpdateError(int retries, std::string url, LLSD body, bool ice_completed, const LLSD &result); + void sendData(const std::string &data); - bool requestVoiceConnection(); - void OnVoiceConnectionRequestSuccess(const LLSD &body); - void OnVoiceConnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result); + virtual void processIceUpdates(); + virtual void onIceUpdateComplete(bool ice_completed, const LLSD &result); + virtual void onIceUpdateError(int retries, std::string url, LLSD body, bool ice_completed, const LLSD &result); - bool connectionStateMachine() override; + virtual void setMuteMic(bool muted); + virtual void setMicGain(F32 volume); + virtual void setSpeakerVolume(F32 volume); - void sendData(const std::string &data) override; - void setMuteMic(bool muted) override; + + bool connectionStateMachine(); LLUUID getRegionID() { return mRegionID; } - void shutDown() override - { - LLMutexLock lock(&mVoiceStateMutex); - mShutDown = true; - } + void shutDown() + { + LLMutexLock lock(&mVoiceStateMutex); + mShutDown = true; + } -protected: + void OnVoiceConnectionRequestSuccess(const LLSD &body); + void OnVoiceConnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result); + + protected: typedef enum e_voice_connection_state { - VOICE_STATE_ERROR = 0x0, - VOICE_STATE_START_SESSION = 0x1, - VOICE_STATE_WAIT_FOR_SESSION_START = 0x2, - VOICE_STATE_REQUEST_CONNECTION = 0x4, - VOICE_STATE_CONNECTION_WAIT = 0x8, - VOICE_STATE_SESSION_ESTABLISHED = 0x10, - VOICE_STATE_SESSION_UP = 0x20, - VOICE_STATE_SESSION_RETRY = 0x40, - VOICE_STATE_DISCONNECT = 0x80, - VOICE_STATE_WAIT_FOR_EXIT = 0x100, - VOICE_STATE_SESSION_EXIT = 0x200, - VOICE_STATE_SESSION_STOPPING = 0x3c0, - VOICE_STATE_SESSION_WAITING = 0x10a + VOICE_STATE_ERROR = 0x0, + VOICE_STATE_START_SESSION = 0x1, + VOICE_STATE_WAIT_FOR_SESSION_START = 0x2, + VOICE_STATE_REQUEST_CONNECTION = 0x4, + VOICE_STATE_CONNECTION_WAIT = 0x8, + VOICE_STATE_SESSION_ESTABLISHED = 0x10, + VOICE_STATE_SESSION_UP = 0x20, + VOICE_STATE_SESSION_RETRY = 0x40, + VOICE_STATE_DISCONNECT = 0x80, + VOICE_STATE_WAIT_FOR_EXIT = 0x100, + VOICE_STATE_SESSION_EXIT = 0x200, + VOICE_STATE_SESSION_STOPPING = 0x3c0, + VOICE_STATE_SESSION_WAITING = 0x10a } EVoiceConnectionState; EVoiceConnectionState mVoiceConnectionState; - LLMutex mVoiceStateMutex; - void setVoiceConnectionState(EVoiceConnectionState new_voice_connection_state) + LLMutex mVoiceStateMutex; + void setVoiceConnectionState(EVoiceConnectionState new_voice_connection_state) { LLMutexLock lock(&mVoiceStateMutex); - if (new_voice_connection_state & VOICE_STATE_SESSION_STOPPING) - { - // the new state is shutdown or restart. + if (new_voice_connection_state & VOICE_STATE_SESSION_STOPPING) + { + // the new state is shutdown or restart. mVoiceConnectionState = new_voice_connection_state; return; - } + } if (mVoiceConnectionState & VOICE_STATE_SESSION_STOPPING) - { - // we're currently shutting down or restarting, so ignore any - // state changes. + { + // we're currently shutting down or restarting, so ignore any + // state changes. return; - } + } mVoiceConnectionState = new_voice_connection_state; } EVoiceConnectionState getVoiceConnectionState() { - if (mVoiceStateMutex.isLocked()) - { + if (mVoiceStateMutex.isLocked()) + { LL_WARNS("Voice") << "LOCKED." << LL_ENDL; - } + } LLMutexLock lock(&mVoiceStateMutex); return mVoiceConnectionState; } + virtual bool requestVoiceConnection() = 0; + bool breakVoiceConnection(bool wait); void OnVoiceDisconnectionRequestSuccess(const LLSD &body); void OnVoiceDisconnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result); + LLUUID mRegionID; + LLUUID mViewerSession; + std::string mChannelID; + std::string mChannelSDP; std::string mRemoteChannelSDP; - LLUUID mViewerSession; - - std::string mChannelID; - LLUUID mRegionID; - S32 mParcelLocalID; + bool mMuted; + F32 mMicGain; + F32 mSpeakerVolume; - bool mShutDown; + bool mShutDown; S32 mOutstandingRequests; std::vector mIceCandidates; @@ -901,6 +864,38 @@ protected: llwebrtc::LLWebRTCDataInterface *mWebRTCDataInterface; }; + +class LLVoiceWebRTCSpatialConnection : + public LLVoiceWebRTCConnection +{ + public: + LLVoiceWebRTCSpatialConnection(const LLUUID ®ionID, S32 parcelLocalID, const std::string &channelID); + + virtual ~LLVoiceWebRTCSpatialConnection(); + + void setMuteMic(bool muted) override; + + +protected: + + bool requestVoiceConnection() override; + + S32 mParcelLocalID; +}; + +class LLVoiceWebRTCAdHocConnection : public LLVoiceWebRTCConnection +{ + public: + LLVoiceWebRTCAdHocConnection(const LLUUID ®ionID, const std::string &channelID, const std::string& credentials); + + virtual ~LLVoiceWebRTCAdHocConnection(); + + protected: + bool requestVoiceConnection() override; + + std::string mCredentials; +}; + #define VOICE_ELAPSED LLVoiceTimer(__FUNCTION__); #endif //LL_WebRTC_VOICE_CLIENT_H -- cgit v1.2.3