diff options
Diffstat (limited to 'indra/newview/llvoicechannel.cpp')
-rw-r--r-- | indra/newview/llvoicechannel.cpp | 1369 |
1 files changed, 692 insertions, 677 deletions
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index b0eb8d962c..cf128f381a 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llvoicechannel.cpp * @brief Voice Channel related classes * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, 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$ */ @@ -39,12 +39,11 @@ #include "llcorehttputil.h" LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; -LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; LLVoiceChannel::channel_changed_signal_t LLVoiceChannel::sCurrentVoiceChannelChangedSignal; -BOOL LLVoiceChannel::sSuspended = FALSE; +bool LLVoiceChannel::sSuspended = false; // // Constants @@ -54,552 +53,549 @@ const U32 DEFAULT_RETRIES_COUNT = 3; // // LLVoiceChannel // -LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) : - mSessionID(session_id), - mState(STATE_NO_CHANNEL_INFO), - mSessionName(session_name), - mCallDirection(OUTGOING_CALL), - mIgnoreNextSessionLeave(FALSE), - mCallEndedByAgent(false) +LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) : + mSessionID(session_id), + mState(STATE_NO_CHANNEL_INFO), + mSessionName(session_name), + mCallDirection(OUTGOING_CALL), + mIgnoreNextSessionLeave(false), + mCallEndedByAgent(false) { - mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName; + mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName; - if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second) - { - // a voice channel already exists for this session id, so this instance will be orphaned - // the end result should simply be the failure to make voice calls - LL_WARNS("Voice") << "Duplicate voice channels registered for session_id " << session_id << LL_ENDL; - } + if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second) + { + // a voice channel already exists for this session id, so this instance will be orphaned + // the end result should simply be the failure to make voice calls + LL_WARNS("Voice") << "Duplicate voice channels registered for session_id " << session_id << LL_ENDL; + } } LLVoiceChannel::~LLVoiceChannel() { - if (sSuspendedVoiceChannel == this) - { - sSuspendedVoiceChannel = NULL; - } - if (sCurrentVoiceChannel == this) - { - sCurrentVoiceChannel = NULL; - // Must check instance exists here, the singleton MAY have already been destroyed. - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } - } - - sVoiceChannelMap.erase(mSessionID); - sVoiceChannelURIMap.erase(mURI); -} - -void LLVoiceChannel::setChannelInfo( - const std::string& uri, - const std::string& credentials) -{ - setURI(uri); - - mCredentials = credentials; - - if (mState == STATE_NO_CHANNEL_INFO) - { - if (mURI.empty()) - { - LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs); - LL_WARNS("Voice") << "Received empty URI for channel " << mSessionName << LL_ENDL; - deactivate(); - } - else if (mCredentials.empty()) - { - LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs); - LL_WARNS("Voice") << "Received empty credentials for channel " << mSessionName << LL_ENDL; - deactivate(); - } - else - { - setState(STATE_READY); - - // if we are supposed to be active, reconnect - // this will happen on initial connect, as we request credentials on first use - if (sCurrentVoiceChannel == this) - { - // just in case we got new channel info while active - // should move over to new channel - activate(); - } - } - } -} - -void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal) -{ - if (channelURI != mURI) - { - return; - } - - if (type < BEGIN_ERROR_STATUS) - { - handleStatusChange(type); - } - else - { - handleError(type); - } + if (sSuspendedVoiceChannel == this) + { + sSuspendedVoiceChannel = NULL; + } + if (sCurrentVoiceChannel == this) + { + sCurrentVoiceChannel = NULL; + } + LLVoiceClient::removeObserver(this); + + sVoiceChannelMap.erase(mSessionID); +} + +void LLVoiceChannel::setChannelInfo(const LLSD &channelInfo) +{ + mChannelInfo = channelInfo; + + if (mState == STATE_NO_CHANNEL_INFO) + { + if (mChannelInfo.isUndefined() || !mChannelInfo.isMap() || mChannelInfo.size() == 0) + { + LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs); + LL_WARNS("Voice") << "Received empty channel info for channel " << mSessionName << LL_ENDL; + deactivate(); + } + else + { + setState(STATE_READY); + + // if we are supposed to be active, reconnect + // this will happen on initial connect, as we request credentials on first use + if (sCurrentVoiceChannel == this) + { + // just in case we got new channel info while active + // should move over to new channel + activate(); + } + } + } +} + +void LLVoiceChannel::resetChannelInfo() +{ + mChannelInfo = LLSD(); + mState = STATE_NO_CHANNEL_INFO; +} + +void LLVoiceChannel::onChange(EStatusType type, const LLSD& channelInfo, bool proximal) +{ + LL_DEBUGS("Voice") << "Incoming channel info: " << channelInfo << LL_ENDL; + LL_DEBUGS("Voice") << "Current channel info: " << mChannelInfo << LL_ENDL; + if (mChannelInfo.isUndefined() || (mChannelInfo.isMap() && mChannelInfo.size() == 0)) + { + mChannelInfo = channelInfo; + } + if (!LLVoiceClient::getInstance()->compareChannels(mChannelInfo, channelInfo)) + { + return; + } + + if (type < BEGIN_ERROR_STATUS) + { + handleStatusChange(type); + } + else + { + handleError(type); + } } void LLVoiceChannel::handleStatusChange(EStatusType type) { - // status updates - switch(type) - { - case STATUS_LOGIN_RETRY: + // status updates + switch(type) + { + case STATUS_LOGIN_RETRY: // no user notice - break; - case STATUS_LOGGED_IN: - break; - case STATUS_LEFT_CHANNEL: - if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) - { - // if forceably removed from channel - // update the UI and revert to default channel - deactivate(); - } - mIgnoreNextSessionLeave = FALSE; - break; - case STATUS_JOINING: - if (callStarted()) - { - setState(STATE_RINGING); - } - break; - case STATUS_JOINED: - if (callStarted()) - { - setState(STATE_CONNECTED); - } - default: - break; - } + break; + case STATUS_LOGGED_IN: + break; + case STATUS_LEFT_CHANNEL: + if (callStarted() && !sSuspended) + { + // if forceably removed from channel + // update the UI and revert to default channel + // deactivate will set the State to STATE_HUNG_UP + // so when handleStatusChange is called again during + // shutdown callStarted will return false and deactivate + // won't be called again. + deactivate(); + } + break; + case STATUS_JOINING: + if (callStarted()) + { + setState(STATE_RINGING); + } + break; + case STATUS_JOINED: + if (callStarted()) + { + setState(STATE_CONNECTED); + } + default: + break; + } } // default behavior is to just deactivate channel // derived classes provide specific error messages void LLVoiceChannel::handleError(EStatusType type) { - deactivate(); - setState(STATE_ERROR); + deactivate(); + setState(STATE_ERROR); } -BOOL LLVoiceChannel::isActive() -{ - // only considered active when currently bound channel matches what our channel - return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI; +bool LLVoiceChannel::isActive() const +{ + // only considered active when currently bound channel matches what our channel + return callStarted() && LLVoiceClient::getInstance()->isCurrentChannel(mChannelInfo); } -BOOL LLVoiceChannel::callStarted() +bool LLVoiceChannel::callStarted() const { - return mState >= STATE_CALL_STARTED; + return mState >= STATE_CALL_STARTED; } void LLVoiceChannel::deactivate() { - if (mState >= STATE_RINGING) - { - // ignore session leave event - mIgnoreNextSessionLeave = TRUE; - } - - if (callStarted()) - { - setState(STATE_HUNG_UP); - - //Default mic is OFF when leaving voice calls - if (gSavedSettings.getBOOL("AutoDisengageMic") && - sCurrentVoiceChannel == this && - LLVoiceClient::getInstance()->getUserPTTState()) - { - gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); - LLVoiceClient::getInstance()->setUserPTTState(false); - } - } - LLVoiceClient::getInstance()->removeObserver(this); - - if (sCurrentVoiceChannel == this) - { - // default channel is proximal channel - sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); - sCurrentVoiceChannel->activate(); - } + if (mState >= STATE_RINGING) + { + // ignore session leave event + mIgnoreNextSessionLeave = true; + } + + if (callStarted()) + { + setState(STATE_HUNG_UP); + + //Default mic is OFF when leaving voice calls + if (gSavedSettings.getBOOL("AutoDisengageMic") && + sCurrentVoiceChannel == this && + LLVoiceClient::getInstance()->getUserPTTState()) + { + gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); + LLVoiceClient::getInstance()->setUserPTTState(false); + } + } + LLVoiceClient::removeObserver(this); + + if (sCurrentVoiceChannel == this) + { + // default channel is proximal channel + sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); + sCurrentVoiceChannel->activate(); + } } void LLVoiceChannel::activate() { - if (callStarted()) - { - return; - } - - // deactivate old channel and mark ourselves as the active one - if (sCurrentVoiceChannel != this) - { - // mark as current before deactivating the old channel to prevent - // activating the proximal channel between IM calls - LLVoiceChannel* old_channel = sCurrentVoiceChannel; - sCurrentVoiceChannel = this; - mCallDialogPayload["old_channel_name"] = ""; - if (old_channel) - { - mCallDialogPayload["old_channel_name"] = old_channel->getSessionName(); - old_channel->deactivate(); - } - } - - if (mState == STATE_NO_CHANNEL_INFO) - { - // responsible for setting status to active - getChannelInfo(); - } - else - { - setState(STATE_CALL_STARTED); - } - - LLVoiceClient::getInstance()->addObserver(this); - - //do not send earlier, channel should be initialized, should not be in STATE_NO_CHANNEL_INFO state - sCurrentVoiceChannelChangedSignal(this->mSessionID); -} - -void LLVoiceChannel::getChannelInfo() -{ - // pretend we have everything we need - if (sCurrentVoiceChannel == this) - { - setState(STATE_CALL_STARTED); - } -} - -//static -LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id) -{ - voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id); - if (found_it == sVoiceChannelMap.end()) - { - return NULL; - } - else - { - return found_it->second; - } + if (callStarted()) + { + return; + } + + // deactivate old channel and mark ourselves as the active one + if (sCurrentVoiceChannel != this) + { + // mark as current before deactivating the old channel to prevent + // activating the proximal channel between IM calls + LLVoiceChannel* old_channel = sCurrentVoiceChannel; + sCurrentVoiceChannel = this; + if (old_channel) + { + old_channel->deactivate(); + } + } + + if (mState == STATE_NO_CHANNEL_INFO) + { + // responsible for setting status to active + requestChannelInfo(); + } + else + { + setState(STATE_CALL_STARTED); + } + + LLVoiceClient::addObserver(this); + + //do not send earlier, channel should be initialized, should not be in STATE_NO_CHANNEL_INFO state + sCurrentVoiceChannelChangedSignal(this->mSessionID); } -//static -LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) +void LLVoiceChannel::requestChannelInfo() { - voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri); - if (found_it == sVoiceChannelURIMap.end()) - { - return NULL; - } - else - { - return found_it->second; - } + // pretend we have everything we need + if (sCurrentVoiceChannel == this) + { + setState(STATE_CALL_STARTED); + } } -LLVoiceChannel* LLVoiceChannel::getCurrentVoiceChannel() +//static +LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id) { - return sCurrentVoiceChannel; + voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id); + if (found_it == sVoiceChannelMap.end()) + { + return NULL; + } + else + { + return found_it->second; + } } -void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id) +LLVoiceChannel* LLVoiceChannel::getCurrentVoiceChannel() { - sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID)); - mSessionID = new_session_id; - sVoiceChannelMap.insert(std::make_pair(mSessionID, this)); + return sCurrentVoiceChannel; } -void LLVoiceChannel::setURI(std::string uri) +void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id) { - sVoiceChannelURIMap.erase(mURI); - mURI = uri; - sVoiceChannelURIMap.insert(std::make_pair(mURI, this)); + sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID)); + mSessionID = new_session_id; + sVoiceChannelMap.insert(std::make_pair(mSessionID, this)); } void LLVoiceChannel::setState(EState state) { - switch(state) - { - case STATE_RINGING: - //TODO: remove or redirect this call status notification -// LLCallInfoDialog::show("ringing", mNotifyArgs); - break; - case STATE_CONNECTED: - //TODO: remove or redirect this call status notification -// LLCallInfoDialog::show("connected", mNotifyArgs); - break; - case STATE_HUNG_UP: - //TODO: remove or redirect this call status notification -// LLCallInfoDialog::show("hang_up", mNotifyArgs); - break; - default: - break; - } - - doSetState(state); + switch(state) + { + case STATE_RINGING: + //TODO: remove or redirect this call status notification +// LLCallInfoDialog::show("ringing", mNotifyArgs); + break; + case STATE_CONNECTED: + //TODO: remove or redirect this call status notification +// LLCallInfoDialog::show("connected", mNotifyArgs); + break; + case STATE_HUNG_UP: + //TODO: remove or redirect this call status notification +// LLCallInfoDialog::show("hang_up", mNotifyArgs); + break; + default: + break; + } + + doSetState(state); } void LLVoiceChannel::doSetState(const EState& new_state) { - EState old_state = mState; - mState = new_state; + LL_DEBUGS("Voice") << "session '" << mSessionName << "' state " << mState << ", new_state " << new_state << ": " + << (new_state == STATE_ERROR ? "ERROR" : + new_state == STATE_HUNG_UP ? "HUNG_UP" : + new_state == STATE_READY ? "READY" : + new_state == STATE_CALL_STARTED ? "CALL_STARTED" : + new_state == STATE_RINGING ? "RINGING" : + new_state == STATE_CONNECTED ? "CONNECTED" : + "NO_INFO") + << LL_ENDL; - if (!mStateChangedCallback.empty()) - mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent, mSessionID); + EState old_state = mState; + mState = new_state; + + if (!mStateChangedCallback.empty()) + mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent, mSessionID); } //static void LLVoiceChannel::initClass() { - sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); + sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); } -//static +//static void LLVoiceChannel::suspend() { - if (!sSuspended) - { - sSuspendedVoiceChannel = sCurrentVoiceChannel; - sSuspended = TRUE; - } + if (!sSuspended) + { + sSuspendedVoiceChannel = sCurrentVoiceChannel; + sSuspended = true; + } } -//static +//static void LLVoiceChannel::resume() { - if (sSuspended) - { - if (LLVoiceClient::getInstance()->voiceEnabled()) - { - if (sSuspendedVoiceChannel) - { - sSuspendedVoiceChannel->activate(); - } - else - { - LLVoiceChannelProximal::getInstance()->activate(); - } - } - sSuspended = FALSE; - } + if (sSuspended) + { + if (LLVoiceClient::getInstance()->voiceEnabled()) + { + if (sSuspendedVoiceChannel) + { + sSuspendedVoiceChannel->activate(); + } + else + { + LLVoiceChannelProximal::getInstance()->activate(); + } + } + sSuspended = false; + } } boost::signals2::connection LLVoiceChannel::setCurrentVoiceChannelChangedCallback(channel_changed_callback_t cb, bool at_front) { - if (at_front) - { - return sCurrentVoiceChannelChangedSignal.connect(cb, boost::signals2::at_front); - } - else - { - return sCurrentVoiceChannelChangedSignal.connect(cb); - } + if (at_front) + { + return sCurrentVoiceChannelChangedSignal.connect(cb, boost::signals2::at_front); + } + else + { + return sCurrentVoiceChannelChangedSignal.connect(cb); + } } // // LLVoiceChannelGroup // -LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) : - LLVoiceChannel(session_id, session_name) +LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID &session_id, + const std::string &session_name, + bool is_p2p) : + LLVoiceChannel(session_id, session_name), + mIsP2P(is_p2p) { - mRetries = DEFAULT_RETRIES_COUNT; - mIsRetrying = FALSE; + mRetries = DEFAULT_RETRIES_COUNT; + mIsRetrying = false; } void LLVoiceChannelGroup::deactivate() { - if (callStarted()) - { - LLVoiceClient::getInstance()->leaveNonSpatialChannel(); - } - LLVoiceChannel::deactivate(); -} + if (callStarted()) + { + LLVoiceClient::getInstance()->leaveNonSpatialChannel(); + } + LLVoiceChannel::deactivate(); + + if (mIsP2P) + { + // void the channel info for p2p adhoc channels + // so we request it again, hence throwing up the + // connect dialogue on the other side. + setState(STATE_NO_CHANNEL_INFO); + } + } void LLVoiceChannelGroup::activate() { - if (callStarted()) return; - - LLVoiceChannel::activate(); - - if (callStarted()) - { - // we have the channel info, just need to use it now - LLVoiceClient::getInstance()->setNonSpatialChannel( - mURI, - mCredentials); - - if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel - { - LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionID); - // Adding ad-hoc call participants to Recent People List. - // If it's an outgoing ad-hoc, we can use mInitialTargetIDs that holds IDs of people we - // called(both online and offline) as source to get people for recent (STORM-210). - if (session->isOutgoingAdHoc()) - { - for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin(); - it!=session->mInitialTargetIDs.end();++it) - { - const LLUUID id = *it; - LLRecentPeople::instance().add(id); - } - } - // If this ad-hoc is incoming then trying to get ids of people from mInitialTargetIDs - // would lead to EXT-8246. So in this case we get them from speakers list. - else - { - LLIMModel::addSpeakersToRecent(mSessionID); - } - } - - //Mic default state is OFF on initiating/joining Ad-Hoc/Group calls - if (LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle()) - { - LLVoiceClient::getInstance()->inputUserControlState(true); - } - - } -} - -void LLVoiceChannelGroup::getChannelInfo() -{ - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - std::string url = region->getCapability("ChatSessionRequest"); + if (callStarted()) return; + + LLVoiceChannel::activate(); + + if (callStarted()) + { + // we have the channel info, just need to use it now + LLVoiceClient::getInstance()->setNonSpatialChannel(mChannelInfo, + mIsP2P && (mCallDirection == OUTGOING_CALL), + mIsP2P); + + if (mIsP2P) + { + LLIMModel::addSpeakersToRecent(mSessionID); + } + else + { + if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel + { + LLIMModel::LLIMSession *session = LLIMModel::getInstance()->findIMSession(mSessionID); + // Adding ad-hoc call participants to Recent People List. + // If it's an outgoing ad-hoc, we can use mInitialTargetIDs that holds IDs of people we + // called(both online and offline) as source to get people for recent (STORM-210). + if (session && session->isOutgoingAdHoc()) + { + for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin(); it != session->mInitialTargetIDs.end(); ++it) + { + const LLUUID id = *it; + LLRecentPeople::instance().add(id); + } + } + // If this ad-hoc is incoming then trying to get ids of people from mInitialTargetIDs + // would lead to EXT-8246. So in this case we get them from speakers list. + else + { + LLIMModel::addSpeakersToRecent(mSessionID); + } + } + } + + // Mic default state is OFF on initiating/joining Ad-Hoc/Group calls. It's on for P2P using the AdHoc infra. + + LLVoiceClient::getInstance()->setUserPTTState(mIsP2P); + } +} + +void LLVoiceChannelGroup::requestChannelInfo() +{ + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string url = region->getCapability("ChatSessionRequest"); LLCoros::instance().launch("LLVoiceChannelGroup::voiceCallCapCoro", boost::bind(&LLVoiceChannelGroup::voiceCallCapCoro, this, url)); - } -} - -void LLVoiceChannelGroup::setChannelInfo( - const std::string& uri, - const std::string& credentials) -{ - setURI(uri); - - mCredentials = credentials; - - if (mState == STATE_NO_CHANNEL_INFO) - { - if(!mURI.empty() && !mCredentials.empty()) - { - setState(STATE_READY); - - // if we are supposed to be active, reconnect - // this will happen on initial connect, as we request credentials on first use - if (sCurrentVoiceChannel == this) - { - // just in case we got new channel info while active - // should move over to new channel - activate(); - } - } - else - { - //*TODO: notify user - LL_WARNS("Voice") << "Received invalid credentials for channel " << mSessionName << LL_ENDL; - deactivate(); - } - } - else if ( mIsRetrying ) - { - // we have the channel info, just need to use it now - LLVoiceClient::getInstance()->setNonSpatialChannel( - mURI, - mCredentials); - } + } +} + +void LLVoiceChannelGroup::setChannelInfo(const LLSD& channelInfo) +{ + mChannelInfo = channelInfo; + + if (mState == STATE_NO_CHANNEL_INFO) + { + if(mChannelInfo.isDefined() && mChannelInfo.isMap()) + { + setState(STATE_READY); + + // if we are supposed to be active, reconnect + // this will happen on initial connect, as we request credentials on first use + if (sCurrentVoiceChannel == this) + { + // just in case we got new channel info while active + // should move over to new channel + activate(); + } + } + else + { + //*TODO: notify user + LL_WARNS("Voice") << "Received invalid credentials for channel " << mSessionName << LL_ENDL; + deactivate(); + } + } + else if ( mIsRetrying ) + { + // we have the channel info, just need to use it now + LLVoiceClient::getInstance()->setNonSpatialChannel(channelInfo, + mCallDirection == OUTGOING_CALL, + mIsP2P); + } } void LLVoiceChannelGroup::handleStatusChange(EStatusType type) { - // status updates - switch(type) - { - case STATUS_JOINED: - mRetries = 3; - mIsRetrying = FALSE; - default: - break; - } + // status updates + switch(type) + { + case STATUS_JOINED: + mRetries = 3; + mIsRetrying = false; + default: + break; + } - LLVoiceChannel::handleStatusChange(type); + LLVoiceChannel::handleStatusChange(type); } void LLVoiceChannelGroup::handleError(EStatusType status) { - std::string notify; - switch(status) - { - case ERROR_CHANNEL_LOCKED: - case ERROR_CHANNEL_FULL: - notify = "VoiceChannelFull"; - break; - case ERROR_NOT_AVAILABLE: - //clear URI and credentials - //set the state to be no info - //and activate - if ( mRetries > 0 ) - { - mRetries--; - mIsRetrying = TRUE; - mIgnoreNextSessionLeave = TRUE; - - getChannelInfo(); - return; - } - else - { - notify = "VoiceChannelJoinFailed"; - mRetries = DEFAULT_RETRIES_COUNT; - mIsRetrying = FALSE; - } - - break; - - case ERROR_UNKNOWN: - default: - break; - } - - // notification - if (!notify.empty()) - { - LLNotificationPtr notification = LLNotificationsUtil::add(notify, mNotifyArgs); - // echo to im window - gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); - } - - LLVoiceChannel::handleError(status); + std::string notify; + switch(status) + { + case ERROR_CHANNEL_LOCKED: + case ERROR_CHANNEL_FULL: + notify = "VoiceChannelFull"; + break; + case ERROR_NOT_AVAILABLE: + //clear URI and credentials + //set the state to be no info + //and activate + if ( mRetries > 0 ) + { + mRetries--; + mIsRetrying = true; + mIgnoreNextSessionLeave = true; + + requestChannelInfo(); + return; + } + else + { + notify = "VoiceChannelJoinFailed"; + mRetries = DEFAULT_RETRIES_COUNT; + mIsRetrying = false; + } + + break; + + case ERROR_UNKNOWN: + default: + break; + } + + // notification + if (!notify.empty()) + { + LLNotificationPtr notification = LLNotificationsUtil::add(notify, mNotifyArgs); + // echo to im window + gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); + } + + LLVoiceChannel::handleError(status); } void LLVoiceChannelGroup::setState(EState state) { - switch(state) - { - case STATE_RINGING: - if ( !mIsRetrying ) - { - //TODO: remove or redirect this call status notification -// LLCallInfoDialog::show("ringing", mNotifyArgs); - } + switch(state) + { + case STATE_RINGING: + if ( !mIsRetrying ) + { + //TODO: remove or redirect this call status notification +// LLCallInfoDialog::show("ringing", mNotifyArgs); + } - doSetState(state); - break; - default: - LLVoiceChannel::setState(state); - } + doSetState(state); + break; + default: + LLVoiceChannel::setState(state); + } } void LLVoiceChannelGroup::voiceCallCapCoro(std::string url) @@ -612,6 +608,16 @@ void LLVoiceChannelGroup::voiceCallCapCoro(std::string url) LLSD postData; postData["method"] = "call"; postData["session-id"] = mSessionID; + LLSD altParams; + std::string preferred_voice_server_type = gSavedSettings.getString("VoiceServerType"); + if (preferred_voice_server_type.empty()) + { + // default to the server type associated with the region we're on. + LLVoiceVersionInfo versionInfo = LLVoiceClient::getInstance()->getVersion(); + preferred_voice_server_type = versionInfo.internalVoiceServerType; + } + altParams["preferred_voice_server_type"] = preferred_voice_server_type; + postData["alt_params"] = altParams; LL_INFOS("Voice", "voiceCallCapCoro") << "Generic POST for " << url << LL_ENDL; @@ -651,297 +657,306 @@ void LLVoiceChannelGroup::voiceCallCapCoro(std::string url) LLSD::map_const_iterator iter; for (iter = result.beginMap(); iter != result.endMap(); ++iter) { - LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got " + LL_DEBUGS("Voice") << "LLVoiceChannelGroup::voiceCallCapCoro got " << iter->first << LL_ENDL; } + LL_INFOS("Voice") << "LLVoiceChannelGroup::voiceCallCapCoro got " << result << LL_ENDL; - channelp->setChannelInfo( - result["voice_credentials"]["channel_uri"].asString(), - result["voice_credentials"]["channel_credentials"].asString()); - + channelp->setChannelInfo(result["voice_credentials"]); } // // LLVoiceChannelProximal // -LLVoiceChannelProximal::LLVoiceChannelProximal() : - LLVoiceChannel(LLUUID::null, LLStringUtil::null) +LLVoiceChannelProximal::LLVoiceChannelProximal() : + LLVoiceChannel(LLUUID::null, LLStringUtil::null) { } -BOOL LLVoiceChannelProximal::isActive() +bool LLVoiceChannelProximal::isActive() const { - return callStarted() && LLVoiceClient::getInstance()->inProximalChannel(); + return callStarted() && LLVoiceClient::getInstance()->inProximalChannel(); } void LLVoiceChannelProximal::activate() { - if (callStarted()) return; + if (callStarted()) return; + + if((LLVoiceChannel::sCurrentVoiceChannel != this) && (LLVoiceChannel::getState() == STATE_CONNECTED)) + { + // we're connected to a non-spatial channel, so disconnect. + LLVoiceClient::getInstance()->leaveNonSpatialChannel(); + } - if((LLVoiceChannel::sCurrentVoiceChannel != this) && (LLVoiceChannel::getState() == STATE_CONNECTED)) - { - // we're connected to a non-spatial channel, so disconnect. - LLVoiceClient::getInstance()->leaveNonSpatialChannel(); - } - LLVoiceChannel::activate(); - + LLVoiceClient::getInstance()->activateSpatialChannel(true); + LLVoiceChannel::activate(); } -void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal) +void LLVoiceChannelProximal::onChange(EStatusType type, const LLSD& channelInfo, bool proximal) { - if (!proximal) - { - return; - } + if (!proximal) + { + return; + } - if (type < BEGIN_ERROR_STATUS) - { - handleStatusChange(type); - } - else - { - handleError(type); - } + if (type < BEGIN_ERROR_STATUS) + { + handleStatusChange(type); + } + else + { + handleError(type); + } } void LLVoiceChannelProximal::handleStatusChange(EStatusType status) { - // status updates - switch(status) - { - case STATUS_LEFT_CHANNEL: - // do not notify user when leaving proximal channel - return; - case STATUS_VOICE_DISABLED: - LLVoiceClient::getInstance()->setUserPTTState(false); - gAgent.setVoiceConnected(false); - //skip showing "Voice not available at your current location" when agent voice is disabled (EXT-4749) - if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()) - { - //TODO: remove or redirect this call status notification -// LLCallInfoDialog::show("unavailable", mNotifyArgs); - } - return; - default: - break; - } - LLVoiceChannel::handleStatusChange(status); + // status updates + switch(status) + { + case STATUS_LEFT_CHANNEL: + // do not notify user when leaving proximal channel + return; + case STATUS_VOICE_DISABLED: + LLVoiceClient::getInstance()->setUserPTTState(false); + gAgent.setVoiceConnected(false); + //skip showing "Voice not available at your current location" when agent voice is disabled (EXT-4749) + if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()) + { + //TODO: remove or redirect this call status notification +// LLCallInfoDialog::show("unavailable", mNotifyArgs); + } + return; + default: + break; + } + LLVoiceChannel::handleStatusChange(status); } void LLVoiceChannelProximal::handleError(EStatusType status) { - std::string notify; - switch(status) - { - case ERROR_CHANNEL_LOCKED: - case ERROR_CHANNEL_FULL: - notify = "ProximalVoiceChannelFull"; - break; - default: - break; - } + std::string notify; + switch(status) + { + case ERROR_CHANNEL_LOCKED: + case ERROR_CHANNEL_FULL: + notify = "ProximalVoiceChannelFull"; + break; + default: + break; + } - // notification - if (!notify.empty()) - { - LLNotificationsUtil::add(notify, mNotifyArgs); - } + // notification + if (!notify.empty()) + { + LLNotificationsUtil::add(notify, mNotifyArgs); + } - LLVoiceChannel::handleError(status); + // proximal voice remains up and the provider will try to reconnect. } void LLVoiceChannelProximal::deactivate() { - if (callStarted()) - { - setState(STATE_HUNG_UP); - } + if (callStarted()) + { + setState(STATE_HUNG_UP); + } + LLVoiceClient::removeObserver(this); + LLVoiceClient::getInstance()->activateSpatialChannel(false); } // // LLVoiceChannelP2P // -LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) : - LLVoiceChannelGroup(session_id, session_name), - mOtherUserID(other_user_id), - mReceivedCall(FALSE) +LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID &session_id, + const std::string &session_name, + const LLUUID &other_user_id, + LLVoiceP2POutgoingCallInterface* outgoing_call_interface) : + LLVoiceChannelGroup(session_id, session_name, true), + mOtherUserID(other_user_id), + mReceivedCall(false), + mOutgoingCallInterface(outgoing_call_interface) { - // make sure URI reflects encoded version of other user's agent id - setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); + mChannelInfo = LLVoiceClient::getInstance()->getP2PChannelInfoTemplate(other_user_id); } void LLVoiceChannelP2P::handleStatusChange(EStatusType type) { - LL_INFOS("Voice") << "P2P CALL CHANNEL STATUS CHANGE: incoming=" << int(mReceivedCall) << " newstatus=" << LLVoiceClientStatusObserver::status2string(type) << " (mState=" << mState << ")" << LL_ENDL; - - // status updates - switch(type) - { - case STATUS_LEFT_CHANNEL: - if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) - { - // *TODO: use it to show DECLINE voice notification - if (mState == STATE_RINGING) - { - // other user declined call - LLNotificationsUtil::add("P2PCallDeclined", mNotifyArgs); - } - else - { - // other user hung up, so we didn't end the call - mCallEndedByAgent = false; - } - deactivate(); - } - mIgnoreNextSessionLeave = FALSE; - return; - case STATUS_JOINING: - // because we join session we expect to process session leave event in the future. EXT-7371 - // may be this should be done in the LLVoiceChannel::handleStatusChange. - mIgnoreNextSessionLeave = FALSE; - break; - - default: - break; - } - - LLVoiceChannel::handleStatusChange(type); + LL_INFOS("Voice") << "P2P CALL CHANNEL STATUS CHANGE: incoming=" << int(mReceivedCall) << " newstatus=" << LLVoiceClientStatusObserver::status2string(type) << " (mState=" << mState << ")" << LL_ENDL; + + // status updates + switch(type) + { + case STATUS_LEFT_CHANNEL: + if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) + { + // *TODO: use it to show DECLINE voice notification + if (mState == STATE_RINGING) + { + // other user declined call + LLNotificationsUtil::add("P2PCallDeclined", mNotifyArgs); + } + else + { + // other user hung up, so we didn't end the call + mCallEndedByAgent = false; + } + deactivate(); + } + mIgnoreNextSessionLeave = false; + return; + case STATUS_JOINING: + // because we join session we expect to process session leave event in the future. EXT-7371 + // may be this should be done in the LLVoiceChannel::handleStatusChange. + mIgnoreNextSessionLeave = false; + break; + + default: + break; + } + + LLVoiceChannel::handleStatusChange(type); } void LLVoiceChannelP2P::handleError(EStatusType type) { - switch(type) - { - case ERROR_NOT_AVAILABLE: - LLNotificationsUtil::add("P2PCallNoAnswer", mNotifyArgs); - break; - default: - break; - } + switch(type) + { + case ERROR_NOT_AVAILABLE: + LLNotificationsUtil::add("P2PCallNoAnswer", mNotifyArgs); + break; + default: + break; + } - LLVoiceChannel::handleError(type); + LLVoiceChannel::handleError(type); } void LLVoiceChannelP2P::activate() { - if (callStarted()) return; - - //call will be counted as ended by user unless this variable is changed in handleStatusChange() - mCallEndedByAgent = true; - - LLVoiceChannel::activate(); - - if (callStarted()) - { - // no session handle yet, we're starting the call - if (mSessionHandle.empty()) - { - mReceivedCall = FALSE; - LLVoiceClient::getInstance()->callUser(mOtherUserID); - } - // otherwise answering the call - else - { - if (!LLVoiceClient::getInstance()->answerInvite(mSessionHandle)) - { - mCallEndedByAgent = false; - mSessionHandle.clear(); - handleError(ERROR_UNKNOWN); - return; - } - // using the session handle invalidates it. Clear it out here so we can't reuse it by accident. - mSessionHandle.clear(); - } - - // Add the party to the list of people with which we've recently interacted. - addToTheRecentPeopleList(); - - //Default mic is ON on initiating/joining P2P calls - if (!LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle()) - { - LLVoiceClient::getInstance()->inputUserControlState(true); - } - } -} - -void LLVoiceChannelP2P::getChannelInfo() -{ - // pretend we have everything we need, since P2P doesn't use channel info - if (sCurrentVoiceChannel == this) - { - setState(STATE_CALL_STARTED); - } + if (callStarted()) return; + + //call will be counted as ended by user unless this variable is changed in handleStatusChange() + mCallEndedByAgent = true; + + LLVoiceChannel::activate(); + + if (callStarted()) + { + // no session handle yet, we're starting the call + if (mIncomingCallInterface == nullptr) + { + mReceivedCall = false; + mOutgoingCallInterface->callUser(mOtherUserID); + } + // otherwise answering the call + else + { + if (!mIncomingCallInterface->answerInvite()) + { + mCallEndedByAgent = false; + mIncomingCallInterface.reset(); + handleError(ERROR_UNKNOWN); + return; + } + // using the incoming call interface invalidates it. Clear it out here so we can't reuse it by accident. + mIncomingCallInterface.reset(); + } + + // Add the party to the list of people with which we've recently interacted. + addToTheRecentPeopleList(); + + //Default mic is ON on initiating/joining P2P calls + if (!LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle()) + { + LLVoiceClient::getInstance()->inputUserControlState(true); + } + } +} + +void LLVoiceChannelP2P::deactivate() +{ + if (callStarted()) + { + mOutgoingCallInterface->hangup(); + } + LLVoiceChannel::deactivate(); +} + + +void LLVoiceChannelP2P::requestChannelInfo() +{ + // pretend we have everything we need, since P2P doesn't use channel info + if (sCurrentVoiceChannel == this) + { + setState(STATE_CALL_STARTED); + } } // receiving session from other user who initiated call -void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI) -{ - BOOL needs_activate = FALSE; - if (callStarted()) - { - // defer to lower agent id when already active - if (mOtherUserID < gAgent.getID()) - { - // pretend we haven't started the call yet, so we can connect to this session instead - deactivate(); - needs_activate = TRUE; - } - else - { - // we are active and have priority, invite the other user again - // under the assumption they will join this new session - mSessionHandle.clear(); - LLVoiceClient::getInstance()->callUser(mOtherUserID); - return; - } - } - - mSessionHandle = handle; - - // The URI of a p2p session should always be the other end's SIP URI. - if(!inURI.empty()) - { - setURI(inURI); - } - else - { - LL_WARNS("Voice") << "incoming SIP URL is not provided. Channel may not work properly." << LL_ENDL; - // See LLVoiceClient::sessionAddedEvent() - setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); - } - - mReceivedCall = TRUE; - - if (needs_activate) - { - activate(); - } +void LLVoiceChannelP2P::setChannelInfo(const LLSD& channel_info) +{ + mChannelInfo = channel_info; + bool needs_activate = false; + if (callStarted()) + { + // defer to lower agent id when already active + if (mOtherUserID < gAgent.getID()) + { + // pretend we haven't started the call yet, so we can connect to this session instead + deactivate(); + needs_activate = true; + } + else + { + // we are active and have priority, invite the other user again + // under the assumption they will join this new session + mOutgoingCallInterface->callUser(mOtherUserID); + return; + } + } + + mReceivedCall = true; + if (channel_info.isDefined() && channel_info.isMap()) + { + mIncomingCallInterface = LLVoiceClient::getInstance()->getIncomingCallInterface(channel_info); + } + if (needs_activate) + { + activate(); + } +} + +void LLVoiceChannelP2P::resetChannelInfo() +{ + mChannelInfo = LLVoiceClient::getInstance()->getP2PChannelInfoTemplate(mOtherUserID); + mState = STATE_NO_CHANNEL_INFO; // we have template, not full info } void LLVoiceChannelP2P::setState(EState state) { - LL_INFOS("Voice") << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << LL_ENDL; + LL_INFOS("Voice") << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << LL_ENDL; - if (mReceivedCall) // incoming call - { - // you only "answer" voice invites in p2p mode - // so provide a special purpose message here - if (mReceivedCall && state == STATE_RINGING) - { - //TODO: remove or redirect this call status notification -// LLCallInfoDialog::show("answering", mNotifyArgs); - doSetState(state); - return; - } - } + if (mReceivedCall) // incoming call + { + // you only "answer" voice invites in p2p mode + // so provide a special purpose message here + if (mReceivedCall && state == STATE_RINGING) + { + //TODO: remove or redirect this call status notification + // LLCallInfoDialog::show("answering", mNotifyArgs); + doSetState(state); + return; + } + } - LLVoiceChannel::setState(state); + LLVoiceChannel::setState(state); } void LLVoiceChannelP2P::addToTheRecentPeopleList() { - LLRecentPeople::instance().add(mOtherUserID); + LLRecentPeople::instance().add(mOtherUserID); } |