phoenix-firestorm/indra/newview/llvoicechannel.cpp

945 lines
26 KiB
C++

/**
* @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$
*/
#include "llviewerprecompiledheaders.h"
#include "llagent.h"
#include "llfloaterreg.h"
#include "llimview.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llpanel.h"
#include "llrecentpeople.h"
#include "llviewercontrol.h"
#include "llviewerregion.h"
#include "llvoicechannel.h"
#include "llcorehttputil.h"
LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
LLVoiceChannel::channel_changed_signal_t LLVoiceChannel::sCurrentVoiceChannelChangedSignal;
bool LLVoiceChannel::sSuspended = false;
//
// Constants
//
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)
{
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;
}
}
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);
}
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::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:
// no user notice
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);
}
bool LLVoiceChannel::isActive() const
{
// only considered active when currently bound channel matches what our channel
return callStarted() && LLVoiceClient::getInstance()->isCurrentChannel(mChannelInfo);
}
bool LLVoiceChannel::callStarted() const
{
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();
}
}
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;
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::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::requestChannelInfo()
{
// 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;
}
}
LLVoiceChannel* LLVoiceChannel::getCurrentVoiceChannel()
{
return sCurrentVoiceChannel;
}
void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
{
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);
}
void LLVoiceChannel::doSetState(const EState& new_state)
{
EState old_state = mState;
mState = new_state;
if (!mStateChangedCallback.empty())
mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent, mSessionID);
}
//static
void LLVoiceChannel::initClass()
{
sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
}
//static
void LLVoiceChannel::suspend()
{
if (!sSuspended)
{
sSuspendedVoiceChannel = sCurrentVoiceChannel;
sSuspended = true;
}
}
//static
void LLVoiceChannel::resume()
{
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);
}
}
//
// LLVoiceChannelGroup
//
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;
}
void LLVoiceChannelGroup::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(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 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;
}
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;
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);
}
doSetState(state);
break;
default:
LLVoiceChannel::setState(state);
}
}
void LLVoiceChannelGroup::voiceCallCapCoro(std::string url)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceCallCapCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
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;
LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
if (!channelp)
{
LL_WARNS("Voice") << "Unable to retrieve channel with Id = " << mSessionID << LL_ENDL;
return;
}
if (!status)
{
if (status == LLCore::HttpStatus(HTTP_FORBIDDEN))
{
//403 == no ability
LLNotificationsUtil::add(
"VoiceNotAllowed",
channelp->getNotifyArgs());
}
else
{
LLNotificationsUtil::add(
"VoiceCallGenericError",
channelp->getNotifyArgs());
}
channelp->deactivate();
return;
}
result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
LLSD::map_const_iterator iter;
for (iter = result.beginMap(); iter != result.endMap(); ++iter)
{
LL_DEBUGS("Voice") << "LLVoiceChannelGroup::voiceCallCapCoro got "
<< iter->first << LL_ENDL;
}
LL_INFOS("Voice") << "LLVoiceChannelGroup::voiceCallCapCoro got " << result << LL_ENDL;
channelp->setChannelInfo(result["voice_credentials"]);
}
//
// LLVoiceChannelProximal
//
LLVoiceChannelProximal::LLVoiceChannelProximal() :
LLVoiceChannel(LLUUID::null, LLStringUtil::null)
{
}
bool LLVoiceChannelProximal::isActive() const
{
return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();
}
void LLVoiceChannelProximal::activate()
{
if (callStarted()) return;
if((LLVoiceChannel::sCurrentVoiceChannel != this) && (LLVoiceChannel::getState() == STATE_CONNECTED))
{
// we're connected to a non-spatial channel, so disconnect.
LLVoiceClient::getInstance()->leaveNonSpatialChannel();
}
LLVoiceClient::getInstance()->activateSpatialChannel(true);
LLVoiceChannel::activate();
}
void LLVoiceChannelProximal::onChange(EStatusType type, const LLSD& channelInfo, bool proximal)
{
if (!proximal)
{
return;
}
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);
}
void LLVoiceChannelProximal::handleError(EStatusType status)
{
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);
}
// proximal voice remains up and the provider will try to reconnect.
}
void LLVoiceChannelProximal::deactivate()
{
if (callStarted())
{
setState(STATE_HUNG_UP);
}
LLVoiceClient::getInstance()->removeObserver(this);
LLVoiceClient::getInstance()->activateSpatialChannel(false);
}
//
// LLVoiceChannelP2P
//
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)
{
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);
}
void LLVoiceChannelP2P::handleError(EStatusType type)
{
switch(type)
{
case ERROR_NOT_AVAILABLE:
LLNotificationsUtil::add("P2PCallNoAnswer", mNotifyArgs);
break;
default:
break;
}
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 (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::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::setState(EState state)
{
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;
}
}
LLVoiceChannel::setState(state);
}
void LLVoiceChannelP2P::addToTheRecentPeopleList()
{
LLRecentPeople::instance().add(mOtherUserID);
}