diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/llappviewer.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llfloaterchatterbox.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llfloatervoicedevicesettings.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llimfloater.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llimpanel.cpp | 830 | ||||
| -rw-r--r-- | indra/newview/llimpanel.h | 127 | ||||
| -rw-r--r-- | indra/newview/llimview.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/llvoicechannel.cpp | 872 | ||||
| -rw-r--r-- | indra/newview/llvoicechannel.h | 167 | ||||
| -rw-r--r-- | indra/newview/llvoiceclient.cpp | 2 | 
11 files changed, 1051 insertions, 958 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index dd3937a6ef..d81ce0c4db 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -484,6 +484,7 @@ set(viewer_SOURCE_FILES      llvoclouds.cpp      llvograss.cpp      llvoground.cpp +    llvoicechannel.cpp      llvoiceclient.cpp      llvoiceremotectrl.cpp      llvoicevisualizer.cpp @@ -960,6 +961,7 @@ set(viewer_HEADER_FILES      llvoclouds.h      llvograss.h      llvoground.h +    llvoicechannel.h      llvoiceclient.h      llvoiceremotectrl.h      llvoicevisualizer.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 923a66ee8e..2ff414344a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -49,7 +49,6 @@  #include "llviewerstats.h"  #include "llmd5.h"  #include "llpumpio.h" -#include "llimpanel.h"  #include "llmimetypes.h"  #include "llslurl.h"  #include "llstartup.h" @@ -76,6 +75,7 @@  #include "llteleporthistory.h"  #include "lllocationhistory.h"  #include "llfasttimerview.h" +#include "llvoicechannel.h"  #include "llweb.h"  #include "llsecondlifeurls.h" diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index dea656b0e4..fbf09207fe 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -42,7 +42,7 @@  #include "llfloaterfriends.h"  #include "llfloatergroups.h"  #include "llviewercontrol.h" -#include "llimview.h" +#include "llvoicechannel.h"  #include "llimpanel.h"  // diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp index b64257b11d..aca9198f59 100644 --- a/indra/newview/llfloatervoicedevicesettings.cpp +++ b/indra/newview/llfloatervoicedevicesettings.cpp @@ -43,7 +43,7 @@  #include "llsliderctrl.h"  #include "llviewercontrol.h"  #include "llvoiceclient.h" -#include "llimpanel.h" +#include "llvoicechannel.h"  // Library includes (after viewer)  #include "lluictrlfactory.h" diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 91e383eb14..0e9d7b070a 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -42,7 +42,6 @@  #include "llchiclet.h"  #include "llfloaterchat.h"  #include "llfloaterreg.h" -#include "llimview.h"  #include "lllineeditor.h"  #include "lllogchat.h"  #include "llpanelimcontrolpanel.h" @@ -50,6 +49,7 @@  #include "lltrans.h"  #include "llchathistory.h"  #include "llviewerwindow.h" +#include "llvoicechannel.h"  #include "lltransientfloatermgr.h" diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 163984f740..2d8372db04 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -77,6 +77,7 @@  #include "llviewercontrol.h"  #include "lluictrlfactory.h"  #include "llviewerwindow.h" +#include "llvoicechannel.h"  #include "lllogchat.h"  #include "llweb.h"  #include "llhttpclient.h" @@ -90,7 +91,6 @@  const S32 LINE_HEIGHT = 16;  const S32 MIN_WIDTH = 200;  const S32 MIN_HEIGHT = 130; -const U32 DEFAULT_RETRIES_COUNT = 3;  //  // Statics @@ -100,831 +100,6 @@ static std::string sTitleString = "Instant Message with [NAME]";  static std::string sTypingStartString = "[NAME]: ...";  static std::string sSessionStartString = "Starting session with [NAME] please wait."; -LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; -LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; -LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; -LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; - -BOOL LLVoiceChannel::sSuspended = FALSE; - - - -class LLVoiceCallCapResponder : public LLHTTPClient::Responder -{ -public: -	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; - -	virtual void error(U32 status, const std::string& reason);	// called with bad status codes -	virtual void result(const LLSD& content); - -private: -	LLUUID mSessionID; -}; - - -void LLVoiceCallCapResponder::error(U32 status, const std::string& reason) -{ -	llwarns << "LLVoiceCallCapResponder::error(" -		<< status << ": " << reason << ")" -		<< llendl; -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); -	if ( channelp ) -	{ -		if ( 403 == status ) -		{ -			//403 == no ability -			LLNotifications::instance().add( -				"VoiceNotAllowed", -				channelp->getNotifyArgs()); -		} -		else -		{ -			LLNotifications::instance().add( -				"VoiceCallGenericError", -				channelp->getNotifyArgs()); -		} -		channelp->deactivate(); -	} -} - -void LLVoiceCallCapResponder::result(const LLSD& content) -{ -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); -	if (channelp) -	{ -		//*TODO: DEBUG SPAM -		LLSD::map_const_iterator iter; -		for(iter = content.beginMap(); iter != content.endMap(); ++iter) -		{ -			llinfos << "LLVoiceCallCapResponder::result got "  -				<< iter->first << llendl; -		} - -		channelp->setChannelInfo( -			content["voice_credentials"]["channel_uri"].asString(), -			content["voice_credentials"]["channel_credentials"].asString()); -	} -} - -// -// LLVoiceChannel -// -LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :  -	mSessionID(session_id),  -	mState(STATE_NO_CHANNEL_INFO),  -	mSessionName(session_name), -	mIgnoreNextSessionLeave(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 -		llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl; -	} - -	LLVoiceClient::getInstance()->addObserver(this); -} - -LLVoiceChannel::~LLVoiceChannel() -{ -	// Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed. -	if(gVoiceClient) -	{ -		gVoiceClient->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()) -		{ -			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); -			llwarns << "Received empty URI for channel " << mSessionName << llendl; -			deactivate(); -		} -		else if (mCredentials.empty()) -		{ -			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); -			llwarns << "Received empty credentials for channel " << mSessionName << llendl; -			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); -	} -} - -void LLVoiceChannel::handleStatusChange(EStatusType type) -{ -	// status updates -	switch(type) -	{ -	case STATUS_LOGIN_RETRY: -		//mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); -		LLNotifications::instance().add("VoiceLoginRetry"); -		break; -	case STATUS_LOGGED_IN: -		//if (!mLoginNotificationHandle.isDead()) -		//{ -		//	LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); -		//	if (notifyp) -		//	{ -		//		notifyp->close(); -		//	} -		//	mLoginNotificationHandle.markDead(); -		//} -		break; -	case STATUS_LEFT_CHANNEL: -		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) -		{ -			// if forceably removed from channel -			// update the UI and revert to default channel -			LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs); -			deactivate(); -		} -		mIgnoreNextSessionLeave = FALSE; -		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() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;  -} - -BOOL LLVoiceChannel::callStarted() -{ -	return mState >= STATE_CALL_STARTED; -} - -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 (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this) -		{ -			gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); -		} -	} - -	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 -		getChannelInfo(); -	} -	else -	{ -		setState(STATE_CALL_STARTED); -	} -} - -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; -	} -} - -//static  -LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) -{ -	voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri); -	if (found_it == sVoiceChannelURIMap.end()) -	{ -		return NULL; -	} -	else -	{ -		return found_it->second; -	} -} - -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::setURI(std::string uri) -{ -	sVoiceChannelURIMap.erase(mURI); -	mURI = uri; -	sVoiceChannelURIMap.insert(std::make_pair(mURI, this)); -} - -void LLVoiceChannel::setState(EState state) -{ -	switch(state) -	{ -	case STATE_RINGING: -		gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); -		break; -	case STATE_CONNECTED: -		gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs); -		break; -	case STATE_HUNG_UP: -		gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs); -		break; -	default: -		break; -	} - -	mState = state; -} - -void LLVoiceChannel::toggleCallWindowIfNeeded(EState state) -{ -	if (state == STATE_CONNECTED) -	{ -		LLFloaterReg::showInstance("voice_call", mSessionID); -	} -	// By checking that current state is CONNECTED we make sure that the call window -	// has been shown, hence there's something to hide. This helps when user presses -	// the "End call" button right after initiating the call. -	// *TODO: move this check to LLFloaterCall? -	else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED) -	{ -		LLFloaterReg::hideInstance("voice_call", 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 (gVoiceClient->voiceEnabled()) -		{ -			if (sSuspendedVoiceChannel) -			{ -				sSuspendedVoiceChannel->activate(); -			} -			else -			{ -				LLVoiceChannelProximal::getInstance()->activate(); -			} -		} -		sSuspended = FALSE; -	} -} - - -// -// LLVoiceChannelGroup -// - -LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :  -	LLVoiceChannel(session_id, session_name) -{ -	mRetries = DEFAULT_RETRIES_COUNT; -	mIsRetrying = FALSE; -} - -void LLVoiceChannelGroup::deactivate() -{ -	if (callStarted()) -	{ -		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); -	} -	LLVoiceChannel::deactivate(); -} - -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 0 // *TODO -		if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel -		{ -			// Add the party to the list of people with which we've recently interacted. -			for (/*people in the chat*/) -				LLRecentPeople::instance().add(buddy_id); -		} -#endif -	} -} - -void LLVoiceChannelGroup::getChannelInfo() -{ -	LLViewerRegion* region = gAgent.getRegion(); -	if (region) -	{ -		std::string url = region->getCapability("ChatSessionRequest"); -		LLSD data; -		data["method"] = "call"; -		data["session-id"] = mSessionID; -		LLHTTPClient::post(url, -						   data, -						   new LLVoiceCallCapResponder(mSessionID)); -	} -} - -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 -			llwarns << "Received invalid credentials for channel " << mSessionName << llendl; -			deactivate(); -		} -	} -	else if ( mIsRetrying ) -	{ -		// we have the channel info, just need to use it now -		LLVoiceClient::getInstance()->setNonSpatialChannel( -			mURI, -			mCredentials); -	} -} - -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; - -			getChannelInfo(); -			return; -		} -		else -		{ -			notify = "VoiceChannelJoinFailed"; -			mRetries = DEFAULT_RETRIES_COUNT; -			mIsRetrying = FALSE; -		} - -		break; - -	case ERROR_UNKNOWN: -	default: -		break; -	} - -	// notification -	if (!notify.empty()) -	{ -		LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs); -		// echo to im window -		gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); -	} - -	LLVoiceChannel::handleError(status); -} - -void LLVoiceChannelGroup::setState(EState state) -{ -	// HACK: Open/close the call window if needed. -	toggleCallWindowIfNeeded(state); - -	switch(state) -	{ -	case STATE_RINGING: -		if ( !mIsRetrying ) -		{ -			gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); -		} - -		mState = state; -		break; -	default: -		LLVoiceChannel::setState(state); -	} -} - -// -// LLVoiceChannelProximal -// -LLVoiceChannelProximal::LLVoiceChannelProximal() :  -	LLVoiceChannel(LLUUID::null, LLStringUtil::null) -{ -	activate(); -} - -BOOL LLVoiceChannelProximal::isActive() -{ -	return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();  -} - -void LLVoiceChannelProximal::activate() -{ -	if (callStarted()) return; - -	LLVoiceChannel::activate(); - -	if (callStarted()) -	{ -		// this implicitly puts you back in the spatial channel -		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); -	} -} - -void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, 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: -		 gIMMgr->addSystemMessage(LLUUID::null, "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()) -	{ -		LLNotifications::instance().add(notify, mNotifyArgs); -	} - -	LLVoiceChannel::handleError(status); -} - -void LLVoiceChannelProximal::deactivate() -{ -	if (callStarted()) -	{ -		setState(STATE_HUNG_UP); -	} -} - - -// -// 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) -{ -	// make sure URI reflects encoded version of other user's agent id -	setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); -} - -void LLVoiceChannelP2P::handleStatusChange(EStatusType type) -{ -	// status updates -	switch(type) -	{ -	case STATUS_LEFT_CHANNEL: -		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) -		{ -			if (mState == STATE_RINGING) -			{ -				// other user declined call -				LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs); -			} -			else -			{ -				// other user hung up -				LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs); -			} -			deactivate(); -		} -		mIgnoreNextSessionLeave = FALSE; -		return; -	default: -		break; -	} - -	LLVoiceChannel::handleStatusChange(type); -} - -void LLVoiceChannelP2P::handleError(EStatusType type) -{ -	switch(type) -	{ -	case ERROR_NOT_AVAILABLE: -		LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs); -		break; -	default: -		break; -	} - -	LLVoiceChannel::handleError(type); -} - -void LLVoiceChannelP2P::activate() -{ -	if (callStarted()) return; - -	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 -		{ -			LLVoiceClient::getInstance()->answerInvite(mSessionHandle); -			 -			// 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. -		LLRecentPeople::instance().add(mOtherUserID); -	} -} - -void LLVoiceChannelP2P::getChannelInfo() -{ -	// 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 -	{ -		setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); -	} -	 -	mReceivedCall = TRUE; - -	if (needs_activate) -	{ -		activate(); -	} -} - -void LLVoiceChannelP2P::setState(EState state) -{ -	// HACK: Open/close the call window if needed. -	toggleCallWindowIfNeeded(state); - -	// you only "answer" voice invites in p2p mode -	// so provide a special purpose message here -	if (mReceivedCall && state == STATE_RINGING) -	{ -		gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs); -		mState = state; -		return; -	} -	LLVoiceChannel::setState(state); -} -  //  // LLFloaterIMPanel @@ -1905,6 +1080,9 @@ bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const  			session_id);  		if ( floaterp ) floaterp->closeFloater(FALSE); + + +  	}  	return false;  } diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index 4e306c7fab..31b5c5c127 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -50,133 +50,6 @@ class LLIMSpeakerMgr;  class LLPanelActiveSpeakers;  class LLPanelChatControlPanel; -class LLVoiceChannel : public LLVoiceClientStatusObserver -{ -public: -	typedef enum e_voice_channel_state -	{ -		STATE_NO_CHANNEL_INFO, -		STATE_ERROR, -		STATE_HUNG_UP, -		STATE_READY, -		STATE_CALL_STARTED, -		STATE_RINGING, -		STATE_CONNECTED -	} EState; - -	LLVoiceChannel(const LLUUID& session_id, const std::string& session_name); -	virtual ~LLVoiceChannel(); - -	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); - -	virtual void handleStatusChange(EStatusType status); -	virtual void handleError(EStatusType status); -	virtual void deactivate(); -	virtual void activate(); -	virtual void setChannelInfo( -		const std::string& uri, -		const std::string& credentials); -	virtual void getChannelInfo(); -	virtual BOOL isActive(); -	virtual BOOL callStarted(); -	const std::string& getSessionName() const { return mSessionName; } - -	const LLUUID getSessionID() { return mSessionID; } -	EState getState() { return mState; } - -	void updateSessionID(const LLUUID& new_session_id); -	const LLSD& getNotifyArgs() { return mNotifyArgs; } - -	static LLVoiceChannel* getChannelByID(const LLUUID& session_id); -	static LLVoiceChannel* getChannelByURI(std::string uri); -	static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; } -	static void initClass(); -	 -	static void suspend(); -	static void resume(); - -protected: -	virtual void setState(EState state); -	void toggleCallWindowIfNeeded(EState state); -	void setURI(std::string uri); - -	std::string	mURI; -	std::string	mCredentials; -	LLUUID		mSessionID; -	EState		mState; -	std::string	mSessionName; -	LLSD mNotifyArgs; -	BOOL		mIgnoreNextSessionLeave; -	LLHandle<LLPanel> mLoginNotificationHandle; - -	typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t; -	static voice_channel_map_t sVoiceChannelMap; - -	typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t; -	static voice_channel_map_uri_t sVoiceChannelURIMap; - -	static LLVoiceChannel* sCurrentVoiceChannel; -	static LLVoiceChannel* sSuspendedVoiceChannel; -	static BOOL sSuspended; -}; - -class LLVoiceChannelGroup : public LLVoiceChannel -{ -public: -	LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name); - -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -	/*virtual*/ void activate(); -	/*virtual*/ void deactivate(); -	/*vritual*/ void setChannelInfo( -		const std::string& uri, -		const std::string& credentials); -	/*virtual*/ void getChannelInfo(); - -protected: -	virtual void setState(EState state); - -private: -	U32 mRetries; -	BOOL mIsRetrying; -}; - -class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal> -{ -public: -	LLVoiceChannelProximal(); - -	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -	/*virtual*/ BOOL isActive(); -	/*virtual*/ void activate(); -	/*virtual*/ void deactivate(); - -}; - -class LLVoiceChannelP2P : public LLVoiceChannelGroup -{ -public: -	LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id); - -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -    /*virtual*/ void activate(); -	/*virtual*/ void getChannelInfo(); - -	void setSessionHandle(const std::string& handle, const std::string &inURI); - -protected: -	virtual void setState(EState state); - -private: -	std::string	mSessionHandle; -	LLUUID		mOtherUserID; -	BOOL		mReceivedCall; -}; -  class LLFloaterIMPanel : public LLFloater  {  public: diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 59cd9cec86..164da4136f 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -70,6 +70,7 @@  #include "llviewerwindow.h"  #include "llnotify.h"  #include "llviewerregion.h" +#include "llvoicechannel.h"  #include "lltrans.h"  #include "llrecentpeople.h" diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp new file mode 100644 index 0000000000..96fcf61e62 --- /dev/null +++ b/indra/newview/llvoicechannel.cpp @@ -0,0 +1,872 @@ +/**  + * @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 "llagent.h" +#include "llfloaterreg.h" +#include "llimview.h" +#include "llnotifications.h" +#include "llpanel.h" +#include "llrecentpeople.h" +#include "llviewercontrol.h" +#include "llvoicechannel.h" + + +LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; +LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; +LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; +LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; + +BOOL LLVoiceChannel::sSuspended = FALSE; + +// +// Constants +// +const U32 DEFAULT_RETRIES_COUNT = 3; + + +class LLVoiceCallCapResponder : public LLHTTPClient::Responder +{ +public: +	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; + +	virtual void error(U32 status, const std::string& reason);	// called with bad status codes +	virtual void result(const LLSD& content); + +private: +	LLUUID mSessionID; +}; + + +void LLVoiceCallCapResponder::error(U32 status, const std::string& reason) +{ +	llwarns << "LLVoiceCallCapResponder::error(" +		<< status << ": " << reason << ")" +		<< llendl; +	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); +	if ( channelp ) +	{ +		if ( 403 == status ) +		{ +			//403 == no ability +			LLNotifications::instance().add( +				"VoiceNotAllowed", +				channelp->getNotifyArgs()); +		} +		else +		{ +			LLNotifications::instance().add( +				"VoiceCallGenericError", +				channelp->getNotifyArgs()); +		} +		channelp->deactivate(); +	} +} + +void LLVoiceCallCapResponder::result(const LLSD& content) +{ +	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); +	if (channelp) +	{ +		//*TODO: DEBUG SPAM +		LLSD::map_const_iterator iter; +		for(iter = content.beginMap(); iter != content.endMap(); ++iter) +		{ +			llinfos << "LLVoiceCallCapResponder::result got "  +				<< iter->first << llendl; +		} + +		channelp->setChannelInfo( +			content["voice_credentials"]["channel_uri"].asString(), +			content["voice_credentials"]["channel_credentials"].asString()); +	} +} + +// +// LLVoiceChannel +// +LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :  +	mSessionID(session_id),  +	mState(STATE_NO_CHANNEL_INFO),  +	mSessionName(session_name), +	mIgnoreNextSessionLeave(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 +		llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl; +	} + +	LLVoiceClient::getInstance()->addObserver(this); +} + +LLVoiceChannel::~LLVoiceChannel() +{ +	// Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed. +	if(gVoiceClient) +	{ +		gVoiceClient->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()) +		{ +			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); +			llwarns << "Received empty URI for channel " << mSessionName << llendl; +			deactivate(); +		} +		else if (mCredentials.empty()) +		{ +			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); +			llwarns << "Received empty credentials for channel " << mSessionName << llendl; +			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); +	} +} + +void LLVoiceChannel::handleStatusChange(EStatusType type) +{ +	// status updates +	switch(type) +	{ +	case STATUS_LOGIN_RETRY: +		//mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); +		LLNotifications::instance().add("VoiceLoginRetry"); +		break; +	case STATUS_LOGGED_IN: +		//if (!mLoginNotificationHandle.isDead()) +		//{ +		//	LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); +		//	if (notifyp) +		//	{ +		//		notifyp->close(); +		//	} +		//	mLoginNotificationHandle.markDead(); +		//} +		break; +	case STATUS_LEFT_CHANNEL: +		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) +		{ +			// if forceably removed from channel +			// update the UI and revert to default channel +			LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs); +			deactivate(); +		} +		mIgnoreNextSessionLeave = FALSE; +		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() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;  +} + +BOOL LLVoiceChannel::callStarted() +{ +	return mState >= STATE_CALL_STARTED; +} + +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 (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this) +		{ +			gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); +		} +	} + +	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 +		getChannelInfo(); +	} +	else +	{ +		setState(STATE_CALL_STARTED); +	} +} + +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; +	} +} + +//static  +LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) +{ +	voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri); +	if (found_it == sVoiceChannelURIMap.end()) +	{ +		return NULL; +	} +	else +	{ +		return found_it->second; +	} +} + +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::setURI(std::string uri) +{ +	sVoiceChannelURIMap.erase(mURI); +	mURI = uri; +	sVoiceChannelURIMap.insert(std::make_pair(mURI, this)); +} + +void LLVoiceChannel::setState(EState state) +{ +	switch(state) +	{ +	case STATE_RINGING: +		gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); +		break; +	case STATE_CONNECTED: +		gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs); +		break; +	case STATE_HUNG_UP: +		gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs); +		break; +	default: +		break; +	} + +	mState = state; +} + +void LLVoiceChannel::toggleCallWindowIfNeeded(EState state) +{ +	if (state == STATE_CONNECTED) +	{ +		LLFloaterReg::showInstance("voice_call", mSessionID); +	} +	// By checking that current state is CONNECTED we make sure that the call window +	// has been shown, hence there's something to hide. This helps when user presses +	// the "End call" button right after initiating the call. +	// *TODO: move this check to LLFloaterCall? +	else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED) +	{ +		LLFloaterReg::hideInstance("voice_call", 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 (gVoiceClient->voiceEnabled()) +		{ +			if (sSuspendedVoiceChannel) +			{ +				sSuspendedVoiceChannel->activate(); +			} +			else +			{ +				LLVoiceChannelProximal::getInstance()->activate(); +			} +		} +		sSuspended = FALSE; +	} +} + + +// +// LLVoiceChannelGroup +// + +LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :  +	LLVoiceChannel(session_id, session_name) +{ +	mRetries = DEFAULT_RETRIES_COUNT; +	mIsRetrying = FALSE; +} + +void LLVoiceChannelGroup::deactivate() +{ +	if (callStarted()) +	{ +		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); +	} +	LLVoiceChannel::deactivate(); +} + +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 0 // *TODO +		if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel +		{ +			// Add the party to the list of people with which we've recently interacted. +			for (/*people in the chat*/) +				LLRecentPeople::instance().add(buddy_id); +		} +#endif +	} +} + +void LLVoiceChannelGroup::getChannelInfo() +{ +	LLViewerRegion* region = gAgent.getRegion(); +	if (region) +	{ +		std::string url = region->getCapability("ChatSessionRequest"); +		LLSD data; +		data["method"] = "call"; +		data["session-id"] = mSessionID; +		LLHTTPClient::post(url, +						   data, +						   new LLVoiceCallCapResponder(mSessionID)); +	} +} + +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 +			llwarns << "Received invalid credentials for channel " << mSessionName << llendl; +			deactivate(); +		} +	} +	else if ( mIsRetrying ) +	{ +		// we have the channel info, just need to use it now +		LLVoiceClient::getInstance()->setNonSpatialChannel( +			mURI, +			mCredentials); +	} +} + +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; + +			getChannelInfo(); +			return; +		} +		else +		{ +			notify = "VoiceChannelJoinFailed"; +			mRetries = DEFAULT_RETRIES_COUNT; +			mIsRetrying = FALSE; +		} + +		break; + +	case ERROR_UNKNOWN: +	default: +		break; +	} + +	// notification +	if (!notify.empty()) +	{ +		LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs); +		// echo to im window +		gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); +	} + +	LLVoiceChannel::handleError(status); +} + +void LLVoiceChannelGroup::setState(EState state) +{ +	// HACK: Open/close the call window if needed. +	toggleCallWindowIfNeeded(state); + +	switch(state) +	{ +	case STATE_RINGING: +		if ( !mIsRetrying ) +		{ +			gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); +		} + +		mState = state; +		break; +	default: +		LLVoiceChannel::setState(state); +	} +} + +// +// LLVoiceChannelProximal +// +LLVoiceChannelProximal::LLVoiceChannelProximal() :  +	LLVoiceChannel(LLUUID::null, LLStringUtil::null) +{ +	activate(); +} + +BOOL LLVoiceChannelProximal::isActive() +{ +	return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();  +} + +void LLVoiceChannelProximal::activate() +{ +	if (callStarted()) return; + +	LLVoiceChannel::activate(); + +	if (callStarted()) +	{ +		// this implicitly puts you back in the spatial channel +		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); +	} +} + +void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, 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: +		 gIMMgr->addSystemMessage(LLUUID::null, "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()) +	{ +		LLNotifications::instance().add(notify, mNotifyArgs); +	} + +	LLVoiceChannel::handleError(status); +} + +void LLVoiceChannelProximal::deactivate() +{ +	if (callStarted()) +	{ +		setState(STATE_HUNG_UP); +	} +} + + +// +// 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) +{ +	// make sure URI reflects encoded version of other user's agent id +	setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); +} + +void LLVoiceChannelP2P::handleStatusChange(EStatusType type) +{ +	// status updates +	switch(type) +	{ +	case STATUS_LEFT_CHANNEL: +		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) +		{ +			if (mState == STATE_RINGING) +			{ +				// other user declined call +				LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs); +			} +			else +			{ +				// other user hung up +				LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs); +			} +			deactivate(); +		} +		mIgnoreNextSessionLeave = FALSE; +		return; +	default: +		break; +	} + +	LLVoiceChannel::handleStatusChange(type); +} + +void LLVoiceChannelP2P::handleError(EStatusType type) +{ +	switch(type) +	{ +	case ERROR_NOT_AVAILABLE: +		LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs); +		break; +	default: +		break; +	} + +	LLVoiceChannel::handleError(type); +} + +void LLVoiceChannelP2P::activate() +{ +	if (callStarted()) return; + +	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 +		{ +			LLVoiceClient::getInstance()->answerInvite(mSessionHandle); +			 +			// 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. +		LLRecentPeople::instance().add(mOtherUserID); +	} +} + +void LLVoiceChannelP2P::getChannelInfo() +{ +	// 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 +	{ +		setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); +	} +	 +	mReceivedCall = TRUE; + +	if (needs_activate) +	{ +		activate(); +	} +} + +void LLVoiceChannelP2P::setState(EState state) +{ +	// HACK: Open/close the call window if needed. +	toggleCallWindowIfNeeded(state); + +	// you only "answer" voice invites in p2p mode +	// so provide a special purpose message here +	if (mReceivedCall && state == STATE_RINGING) +	{ +		gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs); +		mState = state; +		return; +	} +	LLVoiceChannel::setState(state); +} diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h new file mode 100644 index 0000000000..4a9100fba6 --- /dev/null +++ b/indra/newview/llvoicechannel.h @@ -0,0 +1,167 @@ +/**  + * @file llvoicechannel.h + * @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$ + */ + +#ifndef LL_VOICECHANNEL_H +#define LL_VOICECHANNEL_H + +#include "llvoiceclient.h" + +class LLPanel; + +class LLVoiceChannel : public LLVoiceClientStatusObserver +{ +public: +	typedef enum e_voice_channel_state +	{ +		STATE_NO_CHANNEL_INFO, +		STATE_ERROR, +		STATE_HUNG_UP, +		STATE_READY, +		STATE_CALL_STARTED, +		STATE_RINGING, +		STATE_CONNECTED +	} EState; + +	LLVoiceChannel(const LLUUID& session_id, const std::string& session_name); +	virtual ~LLVoiceChannel(); + +	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + +	virtual void handleStatusChange(EStatusType status); +	virtual void handleError(EStatusType status); +	virtual void deactivate(); +	virtual void activate(); +	virtual void setChannelInfo( +		const std::string& uri, +		const std::string& credentials); +	virtual void getChannelInfo(); +	virtual BOOL isActive(); +	virtual BOOL callStarted(); +	const std::string& getSessionName() const { return mSessionName; } + +	const LLUUID getSessionID() { return mSessionID; } +	EState getState() { return mState; } + +	void updateSessionID(const LLUUID& new_session_id); +	const LLSD& getNotifyArgs() { return mNotifyArgs; } + +	static LLVoiceChannel* getChannelByID(const LLUUID& session_id); +	static LLVoiceChannel* getChannelByURI(std::string uri); +	static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; } +	static void initClass(); +	 +	static void suspend(); +	static void resume(); + +protected: +	virtual void setState(EState state); +	void toggleCallWindowIfNeeded(EState state); +	void setURI(std::string uri); + +	std::string	mURI; +	std::string	mCredentials; +	LLUUID		mSessionID; +	EState		mState; +	std::string	mSessionName; +	LLSD mNotifyArgs; +	BOOL		mIgnoreNextSessionLeave; +	LLHandle<LLPanel> mLoginNotificationHandle; + +	typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t; +	static voice_channel_map_t sVoiceChannelMap; + +	typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t; +	static voice_channel_map_uri_t sVoiceChannelURIMap; + +	static LLVoiceChannel* sCurrentVoiceChannel; +	static LLVoiceChannel* sSuspendedVoiceChannel; +	static BOOL sSuspended; +}; + +class LLVoiceChannelGroup : public LLVoiceChannel +{ +public: +	LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name); + +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +	/*virtual*/ void activate(); +	/*virtual*/ void deactivate(); +	/*vritual*/ void setChannelInfo( +		const std::string& uri, +		const std::string& credentials); +	/*virtual*/ void getChannelInfo(); + +protected: +	virtual void setState(EState state); + +private: +	U32 mRetries; +	BOOL mIsRetrying; +}; + +class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal> +{ +public: +	LLVoiceChannelProximal(); + +	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +	/*virtual*/ BOOL isActive(); +	/*virtual*/ void activate(); +	/*virtual*/ void deactivate(); + +}; + +class LLVoiceChannelP2P : public LLVoiceChannelGroup +{ +public: +	LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id); + +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +    /*virtual*/ void activate(); +	/*virtual*/ void getChannelInfo(); + +	void setSessionHandle(const std::string& handle, const std::string &inURI); + +protected: +	virtual void setState(EState state); + +private: +	std::string	mSessionHandle; +	LLUUID		mOtherUserID; +	BOOL		mReceivedCall; +}; + +#endif  // LL_VOICECHANNEL_H diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 02f63a848b..2834284a9b 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -57,13 +57,13 @@  #include "llagent.h"  #include "llcachename.h"  #include "llimview.h" // for LLIMMgr -#include "llimpanel.h" // for LLVoiceChannel  #include "llparcel.h"  #include "llviewerparcelmgr.h"  #include "llfirstuse.h"  #include "llviewerwindow.h"  #include "llviewercamera.h"  #include "llvoavatarself.h" +#include "llvoicechannel.h"  #include "llfloaterfriends.h"  //VIVOX, inorder to refresh communicate panel  #include "llfloaterchat.h"		// for LLFloaterChat::addChat() | 
