123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929 |
- /**
- * @file llvoicechannel.cpp
- * @brief Voice Channel related classes
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llvoicechannel.h"
- #include "llcachename.h"
- #include "llcorehttputil.h"
- #include "llnotifications.h"
- #include "llagent.h"
- #include "llcommandhandler.h"
- #include "llimmgr.h"
- #include "llmediactrl.h"
- #include "llviewercontrol.h"
- constexpr U32 DEFAULT_RETRIES_COUNT = 3;
- // Static variables
- LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
- LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
- LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
- bool LLVoiceChannel::sSuspended = false;
- ///////////////////////////////////////////////////////////////////////////////
- // Global command handler for voicecallavatar
- ///////////////////////////////////////////////////////////////////////////////
- class LLVoiceCallAvatarHandler final : public LLCommandHandler
- {
- public:
- LLVoiceCallAvatarHandler()
- : LLCommandHandler("voicecallavatar", UNTRUSTED_THROTTLE)
- {
- }
- bool handle(const LLSD& params, const LLSD&, LLMediaCtrl*) override
- {
- // Make sure we have some parameters
- if (params.size() == 0)
- {
- return false;
- }
- // Get the ID
- LLUUID id;
- if (!id.set(params[0], false))
- {
- return false;
- }
- std::string name;
- if (gIMMgrp && gCacheNamep && gCacheNamep->getFullName(id, name))
- {
- // Once the IM panel will be opened, and provided that both the
- // caller and the recipient are voice-enabled, the user will be
- // only one click away from an actual voice call...
- // When no voice is available, this action is still consistent
- // With the "Call" link it is associated with in web profiles.
- gIMMgrp->setFloaterOpen(true);
- gIMMgrp->addSession(name, IM_NOTHING_SPECIAL, id);
- make_ui_sound("UISndStartIM");
- }
- return true;
- }
- };
- LLVoiceCallAvatarHandler gVoiceCallAvatarHandler;
- ///////////////////////////////////////////////////////////////////////////////
- // LLVoiceChannel class
- ///////////////////////////////////////////////////////////////////////////////
- LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id,
- const std::string& session_name)
- : mSessionID(session_id),
- mState(STATE_NO_CHANNEL_INFO),
- mSessionName(session_name),
- mOutgoingCall(true), // Set to false if needed in setChannelInfo(). HB
- mIgnoreNextSessionLeave(false)
- {
- mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName;
- if (!sVoiceChannelMap.emplace(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
- llwarns << "Duplicate voice channels registered for session_id "
- << session_id << llendl;
- }
- }
- LLVoiceChannel::~LLVoiceChannel()
- {
- if (gVoiceClient.ready()) // Be sure to keep this !
- {
- gVoiceClient.removeObserver(this);
- }
- if (sSuspendedVoiceChannel == this)
- {
- sSuspendedVoiceChannel = NULL;
- }
- if (sCurrentVoiceChannel == this)
- {
- sCurrentVoiceChannel = NULL;
- }
- sVoiceChannelMap.erase(mSessionID);
- }
- void LLVoiceChannel::setChannelInfo(const LLSD& channel_info)
- {
- LL_DEBUGS("Voice") << "New channel info: " << channel_info << LL_ENDL;
- mChannelInfo = channel_info;
- // Possibly fix the call direction (defaulting to outgoing) based on
- // "incoming" presence which is set in LLIMMgr::inviteUserResponse(). HB
- if (mChannelInfo.has("incoming"))
- {
- mOutgoingCall = false;
- }
- if (mState == STATE_NO_CHANNEL_INFO)
- {
- if (mChannelInfo.isUndefined() || !mChannelInfo.isMap() ||
- !mChannelInfo.size())
- {
- gNotifications.add("VoiceChannelJoinFailed", mNotifyArgs);
- 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& channel_info, bool)
- {
- if (mChannelInfo.isUndefined() ||
- (mChannelInfo.isMap() && !mChannelInfo.size()))
- {
- LL_DEBUGS("Voice") << "New channel info: " << channel_info << LL_ENDL;
- mChannelInfo = channel_info;
- }
- else
- {
- LL_DEBUGS("Voice") << "Keeping current channel info: " << mChannelInfo
- << LL_ENDL;
- }
- if (gVoiceClient.compareChannels(mChannelInfo, channel_info))
- {
- if (type < BEGIN_ERROR_STATUS)
- {
- handleStatusChange(type);
- }
- else
- {
- handleError(type);
- }
- }
- }
- void LLVoiceChannel::handleStatusChange(EStatusType type)
- {
- switch (type)
- {
- case STATUS_LOGIN_RETRY:
- gNotifications.add("VoiceLoginRetry");
- break;
- case STATUS_LOGGED_IN:
- break;
- case STATUS_LEFT_CHANNEL:
- if (callStarted() && !sSuspended)
- {
- // If forcibly removed from channel update the UI and revert to
- // default channel.
- gNotifications.add("VoiceChannelDisconnected", mNotifyArgs);
- // This will set the State to STATE_HUNG_UP so when this method
- // is called again during shutdown callStarted() will return
- // false and this deactivate() would not 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()
- {
- // Only considered active when currently bound channel matches what our
- // channel
- return callStarted() && gVoiceClient.isCurrentChannel(mChannelInfo);
- }
- void LLVoiceChannel::deactivate()
- {
- if (mState >= STATE_RINGING)
- {
- // Ignore session leave event
- mIgnoreNextSessionLeave = true;
- }
- if (callStarted())
- {
- setState(STATE_HUNG_UP);
- // Mute the microphone if required when returning to the proximal
- // channel
- if (sCurrentVoiceChannel == this && gVoiceClient.getUserPTTState() &&
- gSavedSettings.getBool("AutoDisengageMic"))
- {
- gSavedSettings.setBool("PTTCurrentlyEnabled", true);
- gVoiceClient.setUserPTTState(false);
- }
- }
- gVoiceClient.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_channelp = sCurrentVoiceChannel;
- sCurrentVoiceChannel = this;
- if (old_channelp)
- {
- old_channelp->deactivate();
- }
- }
- if (mState == STATE_NO_CHANNEL_INFO)
- {
- // Responsible for setting status to active
- requestChannelInfo();
- }
- else
- {
- setState(STATE_CALL_STARTED);
- }
- gVoiceClient.addObserver(this);
- }
- 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 it = sVoiceChannelMap.find(session_id);
- return it != sVoiceChannelMap.end() ? it->second : NULL;
- }
- void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
- {
- sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
- mSessionID = new_session_id;
- sVoiceChannelMap.emplace(mSessionID, this);
- }
- void LLVoiceChannel::setState(EState state)
- {
- if (!gIMMgrp) return;
- switch (state)
- {
- case STATE_RINGING:
- gIMMgrp->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
- break;
- case STATE_CONNECTED:
- gIMMgrp->addSystemMessage(mSessionID, "connected", mNotifyArgs);
- break;
- case STATE_HUNG_UP:
- gIMMgrp->addSystemMessage(mSessionID, "hang_up", mNotifyArgs);
- break;
- default:
- break;
- }
- mState = state;
- }
- //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::voiceEnabled())
- {
- if (sSuspendedVoiceChannel)
- {
- if (sSuspendedVoiceChannel->callStarted())
- {
- // Should have channel data already, restart
- sSuspendedVoiceChannel->setState(STATE_READY);
- }
- // Note: would not do anything if call is already started...
- sSuspendedVoiceChannel->activate();
- }
- else
- {
- LLVoiceChannelProximal::getInstance()->activate();
- }
- }
- sSuspended = false;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLVoiceChannelGroup class
- ///////////////////////////////////////////////////////////////////////////////
- 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;
- }
- //virtual
- void LLVoiceChannelGroup::deactivate()
- {
- if (callStarted())
- {
- gVoiceClient.leaveNonSpatialChannel();
- }
- LLVoiceChannel::deactivate();
- if (mIsP2P)
- {
- // Void the channel info for P2P adhoc channels so that we request it
- // again, hence throwing up the connect dialogue on the other side.
- setState(STATE_NO_CHANNEL_INFO);
- }
- }
- //virtual
- void LLVoiceChannelGroup::activate()
- {
- if (callStarted()) return;
- LLVoiceChannel::activate();
- if (!callStarted())
- {
- return;
- }
- // We have the channel info, just need to use it now.
- gVoiceClient.setNonSpatialChannel(mChannelInfo, mIsP2P && mOutgoingCall,
- mIsP2P);
- // Mic default state is OFF on initiating/joining Ad-Hoc/Group calls while
- // it is on for P2P using the adhoc infra.
- gVoiceClient.setUserPTTState(mIsP2P);
- }
- //static
- void LLVoiceChannelGroup::voiceCallCapCoro(const std::string& url,
- LLUUID session_id)
- {
- LLSD data;
- data["method"] = "call";
- data["session-id"] = session_id;
- LLSD params;
- params["preferred_voice_server_type"] =
- gSavedSettings.getString("VoiceServerType");
- data["alt_params"] = params;
- LLCoreHttpUtil::HttpCoroutineAdapter adapter("voiceCallCapCoro");
- LLSD result = adapter.postAndSuspend(url, data);
- LLCore::HttpStatus status =
- LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
- // Verify that the channel is still open on server reply, and bail if not.
- LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id);
- if (!channelp)
- {
- llinfos << "Got reply for closed session Id: " << session_id
- << ". Ignored." << llendl;
- return;
- }
- if (!status)
- {
- if (status == gStatusForbidden)
- {
- // 403 == no ability
- gNotifications.add("VoiceNotAllowed", channelp->getNotifyArgs());
- }
- else
- {
- gNotifications.add("VoiceCallGenericError",
- channelp->getNotifyArgs());
- }
- channelp->deactivate();
- return;
- }
- result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
- for (LLSD::map_const_iterator iter = result.beginMap(),
- end = result.endMap();
- iter != end; ++iter)
- {
- llinfos << "Got " << iter->first << llendl;
- }
- channelp->setChannelInfo(result["voice_credentials"]);
- }
- //virtual
- void LLVoiceChannelGroup::requestChannelInfo()
- {
- const std::string& url = gAgent.getRegionCapability("ChatSessionRequest");
- if (url.empty())
- {
- return;
- }
- gCoros.launch("LLVoiceChannelGroup::voiceCallCapCoro",
- boost::bind(&LLVoiceChannelGroup::voiceCallCapCoro, url,
- mSessionID));
- }
- //virtual
- void LLVoiceChannelGroup::setChannelInfo(const LLSD& channel_info)
- {
- mChannelInfo = channel_info;
- // Possibly fix the call direction (defaulting to outgoing) based on
- // "incoming" presence which is set in LLIMMgr::inviteUserResponse(). HB
- if (mChannelInfo.has("incoming"))
- {
- mOutgoingCall = false;
- }
- 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
- {
- deactivate();
- }
- }
- else if (mIsRetrying)
- {
- // We have the channel info, just need to use it now
- gVoiceClient.setNonSpatialChannel(mChannelInfo, mOutgoingCall, mIsP2P);
- }
- }
- //virtual
- void LLVoiceChannelGroup::handleStatusChange(EStatusType type)
- {
- // Status updates
- if (type == STATUS_JOINED)
- {
- mRetries = 3;
- mIsRetrying = false;
- }
- LLVoiceChannel::handleStatusChange(type);
- }
- //virtual
- 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 notifp = gNotifications.add(notify, mNotifyArgs);
- // Echo to IM window
- if (gIMMgrp)
- {
- gIMMgrp->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM,
- notifp->getMessage());
- }
- }
- LLVoiceChannel::handleError(status);
- }
- //virtual
- void LLVoiceChannelGroup::setState(EState state)
- {
- if (state == STATE_RINGING)
- {
- if (!mIsRetrying && gIMMgrp)
- {
- gIMMgrp->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
- }
- mState = state;
- }
- else
- {
- LLVoiceChannel::setState(state);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLVoiceChannelProximal class
- ///////////////////////////////////////////////////////////////////////////////
- LLVoiceChannelProximal::LLVoiceChannelProximal()
- : LLVoiceChannel(LLUUID::null, LLStringUtil::null)
- {
- activate();
- }
- //virtual
- bool LLVoiceChannelProximal::isActive()
- {
- return callStarted() && gVoiceClient.inProximalChannel();
- }
- #define LL_NEW_ACTIVATION_ORDER 1
- //virtual
- void LLVoiceChannelProximal::activate()
- {
- if (callStarted()) return;
- #if LL_NEW_ACTIVATION_ORDER
- if (sCurrentVoiceChannel != this && mState == STATE_CONNECTED)
- {
- // We are connected to a non-spatial channel, so disconnect.
- gVoiceClient.leaveNonSpatialChannel();
- }
- #endif
- gVoiceClient.activateSpatialChannel(true);
- LLVoiceChannel::activate();
- #if !LL_NEW_ACTIVATION_ORDER
- if (callStarted())
- {
- // This implicitly puts you back in the spatial channel
- gVoiceClient.leaveNonSpatialChannel();
- }
- #endif
- }
- //virtual
- void LLVoiceChannelProximal::onChange(EStatusType type, const LLSD&,
- bool proximal)
- {
- if (proximal)
- {
- if (type < BEGIN_ERROR_STATUS)
- {
- handleStatusChange(type);
- }
- else
- {
- handleError(type);
- }
- }
- }
- //virtual
- void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
- {
- if (status == STATUS_LEFT_CHANNEL)
- {
- // Do not notify user when leaving proximal channel
- return;
- }
- if (status == STATUS_VOICE_DISABLED)
- {
- gVoiceClient.setUserPTTState(false);
- if (gIMMgrp)
- {
- gIMMgrp->addSystemMessage(LLUUID::null, "unavailable",
- mNotifyArgs);
- }
- return;
- }
- LLVoiceChannel::handleStatusChange(status);
- }
- //virtual
- void LLVoiceChannelProximal::handleError(EStatusType status)
- {
- if (status == ERROR_CHANNEL_LOCKED || status == ERROR_CHANNEL_FULL)
- {
- gNotifications.add("ProximalVoiceChannelFull", mNotifyArgs);
- }
- #if 0 // Proximal voice remains up and the provider will try to reconnect.
- LLVoiceChannel::handleError(status);
- #endif
- }
- //virtual
- void LLVoiceChannelProximal::deactivate()
- {
- if (callStarted())
- {
- setState(STATE_HUNG_UP);
- }
- gVoiceClient.removeObserver(this);
- gVoiceClient.activateSpatialChannel(false);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLVoiceChannelP2P class
- ///////////////////////////////////////////////////////////////////////////////
- LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id,
- const std::string& session_name,
- const LLUUID& other_user_id,
- U32 server_type)
- : LLVoiceChannelGroup(session_id, session_name, true),
- mOtherUserID(other_user_id),
- mVoiceServerType(server_type),
- mReceivedCall(false),
- mVivoxIncomingCall(false)
- {
- }
- //virtual
- void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
- {
- if (type == STATUS_LEFT_CHANNEL)
- {
- if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
- {
- if (mState == STATE_RINGING)
- {
- // Other user declined call
- gNotifications.add("P2PCallDeclined", mNotifyArgs);
- }
- else
- {
- // Other user hung up
- gNotifications.add("VoiceChannelDisconnectedP2P", mNotifyArgs);
- }
- deactivate();
- }
- mIgnoreNextSessionLeave = false;
- return;
- }
- if (type == STATUS_JOINING)
- {
- // Because we join session we expect to process session leave event in
- // the future.
- mIgnoreNextSessionLeave = false;
- }
- LLVoiceChannel::handleStatusChange(type);
- }
- //virtual
- void LLVoiceChannelP2P::handleError(EStatusType type)
- {
- if (type == ERROR_NOT_AVAILABLE)
- {
- gNotifications.add("P2PCallNoAnswer", mNotifyArgs);
- }
- LLVoiceChannel::handleError(type);
- }
- //virtual
- void LLVoiceChannelP2P::activate()
- {
- if (callStarted()) return;
- LLVoiceChannel::activate();
- if (!callStarted())
- {
- return; // Nothing to do for now.
- }
- if (mVivoxIncomingCall)
- {
- // Answer the call
- mVivoxIncomingCall = false;
- if (!gVoiceClient.answerInvite(mChannelInfo))
- {
- handleError(ERROR_UNKNOWN);
- }
- }
- else
- // No session yet, we are starting the call
- {
- mReceivedCall = false;
- gVoiceClient.callUser(mOtherUserID, mVoiceServerType);
- }
- // Default mic is ON on initiating/joining P2P calls
- if (!gVoiceClient.getUserPTTState() && gVoiceClient.getPTTIsToggle())
- {
- gVoiceClient.inputUserControlState(true);
- }
- }
- //virtual
- void LLVoiceChannelP2P::deactivate()
- {
- if (callStarted())
- {
- gVoiceClient.hangup(mVoiceServerType);
- }
- LLVoiceChannel::deactivate();
- }
- //virtual
- void LLVoiceChannelP2P::requestChannelInfo()
- {
- // Pretend we have everything we need, since P2P does not use channel info.
- if (sCurrentVoiceChannel == this)
- {
- setState(STATE_CALL_STARTED);
- }
- }
- // Receiving session from other user who initiated call
- //virtual
- void LLVoiceChannelP2P::setChannelInfo(const LLSD& channel_info)
- {
- mChannelInfo = channel_info;
- // Possibly fix the call direction (defaulting to outgoing) based on
- // "incoming" presence which is set in LLIMMgr::inviteUserResponse(). HB
- if (mChannelInfo.has("incoming"))
- {
- mOutgoingCall = false;
- }
- bool needs_activate = false;
- if (callStarted())
- {
- // Defer to lower agent id when already active
- if (mOtherUserID < gAgentID)
- {
- // Pretend we have not 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
- gVoiceClient.callUser(mOtherUserID, mVoiceServerType);
- return;
- }
- }
- mReceivedCall = true;
- if (channel_info.isDefined() && channel_info.isMap() &&
- gVoiceClient.getVoiceServerType(channel_info) ==
- LLVoiceClient::VIVOX_SERVER)
- {
- mVivoxIncomingCall = true; // This is an incoming Vivox call.
- }
- if (needs_activate)
- {
- activate();
- }
- }
- //virtual
- void LLVoiceChannelP2P::setState(EState state)
- {
- // You only "answer" voice invites in P2P mode so provide a special purpose
- // message here
- if (mReceivedCall && state == STATE_RINGING)
- {
- if (gIMMgrp)
- {
- gIMMgrp->addSystemMessage(mSessionID, "answering", mNotifyArgs);
- }
- mState = state;
- return;
- }
- LLVoiceChannel::setState(state);
- }
|