/indra/newview/llvoicechannel.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 968 lines · 711 code · 115 blank · 142 comment · 113 complexity · a71ab9ff14047e4fb01df7588205ac0e MD5 · raw file

  1. /**
  2. * @file llvoicechannel.cpp
  3. * @brief Voice Channel related classes
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llagent.h"
  28. #include "llfloaterreg.h"
  29. #include "llimview.h"
  30. #include "llnotifications.h"
  31. #include "llnotificationsutil.h"
  32. #include "llpanel.h"
  33. #include "llrecentpeople.h"
  34. #include "llviewercontrol.h"
  35. #include "llvoicechannel.h"
  36. LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
  37. LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
  38. LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
  39. LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
  40. LLVoiceChannel::channel_changed_signal_t LLVoiceChannel::sCurrentVoiceChannelChangedSignal;
  41. BOOL LLVoiceChannel::sSuspended = FALSE;
  42. //
  43. // Constants
  44. //
  45. const U32 DEFAULT_RETRIES_COUNT = 3;
  46. class LLVoiceCallCapResponder : public LLHTTPClient::Responder
  47. {
  48. public:
  49. LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {};
  50. virtual void error(U32 status, const std::string& reason); // called with bad status codes
  51. virtual void result(const LLSD& content);
  52. private:
  53. LLUUID mSessionID;
  54. };
  55. void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
  56. {
  57. LL_WARNS("Voice") << "LLVoiceCallCapResponder::error("
  58. << status << ": " << reason << ")"
  59. << LL_ENDL;
  60. LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
  61. if ( channelp )
  62. {
  63. if ( 403 == status )
  64. {
  65. //403 == no ability
  66. LLNotificationsUtil::add(
  67. "VoiceNotAllowed",
  68. channelp->getNotifyArgs());
  69. }
  70. else
  71. {
  72. LLNotificationsUtil::add(
  73. "VoiceCallGenericError",
  74. channelp->getNotifyArgs());
  75. }
  76. channelp->deactivate();
  77. }
  78. }
  79. void LLVoiceCallCapResponder::result(const LLSD& content)
  80. {
  81. LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
  82. if (channelp)
  83. {
  84. //*TODO: DEBUG SPAM
  85. LLSD::map_const_iterator iter;
  86. for(iter = content.beginMap(); iter != content.endMap(); ++iter)
  87. {
  88. LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got "
  89. << iter->first << LL_ENDL;
  90. }
  91. channelp->setChannelInfo(
  92. content["voice_credentials"]["channel_uri"].asString(),
  93. content["voice_credentials"]["channel_credentials"].asString());
  94. }
  95. }
  96. //
  97. // LLVoiceChannel
  98. //
  99. LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :
  100. mSessionID(session_id),
  101. mState(STATE_NO_CHANNEL_INFO),
  102. mSessionName(session_name),
  103. mCallDirection(OUTGOING_CALL),
  104. mIgnoreNextSessionLeave(FALSE),
  105. mCallEndedByAgent(false)
  106. {
  107. mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName;
  108. if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second)
  109. {
  110. // a voice channel already exists for this session id, so this instance will be orphaned
  111. // the end result should simply be the failure to make voice calls
  112. LL_WARNS("Voice") << "Duplicate voice channels registered for session_id " << session_id << LL_ENDL;
  113. }
  114. }
  115. LLVoiceChannel::~LLVoiceChannel()
  116. {
  117. // Must check instance exists here, the singleton MAY have already been destroyed.
  118. if(LLVoiceClient::instanceExists())
  119. {
  120. LLVoiceClient::getInstance()->removeObserver(this);
  121. }
  122. sVoiceChannelMap.erase(mSessionID);
  123. sVoiceChannelURIMap.erase(mURI);
  124. }
  125. void LLVoiceChannel::setChannelInfo(
  126. const std::string& uri,
  127. const std::string& credentials)
  128. {
  129. setURI(uri);
  130. mCredentials = credentials;
  131. if (mState == STATE_NO_CHANNEL_INFO)
  132. {
  133. if (mURI.empty())
  134. {
  135. LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
  136. LL_WARNS("Voice") << "Received empty URI for channel " << mSessionName << LL_ENDL;
  137. deactivate();
  138. }
  139. else if (mCredentials.empty())
  140. {
  141. LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
  142. LL_WARNS("Voice") << "Received empty credentials for channel " << mSessionName << LL_ENDL;
  143. deactivate();
  144. }
  145. else
  146. {
  147. setState(STATE_READY);
  148. // if we are supposed to be active, reconnect
  149. // this will happen on initial connect, as we request credentials on first use
  150. if (sCurrentVoiceChannel == this)
  151. {
  152. // just in case we got new channel info while active
  153. // should move over to new channel
  154. activate();
  155. }
  156. }
  157. }
  158. }
  159. void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal)
  160. {
  161. if (channelURI != mURI)
  162. {
  163. return;
  164. }
  165. if (type < BEGIN_ERROR_STATUS)
  166. {
  167. handleStatusChange(type);
  168. }
  169. else
  170. {
  171. handleError(type);
  172. }
  173. }
  174. void LLVoiceChannel::handleStatusChange(EStatusType type)
  175. {
  176. // status updates
  177. switch(type)
  178. {
  179. case STATUS_LOGIN_RETRY:
  180. //mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle();
  181. LLNotificationsUtil::add("VoiceLoginRetry");
  182. break;
  183. case STATUS_LOGGED_IN:
  184. //if (!mLoginNotificationHandle.isDead())
  185. //{
  186. // LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get();
  187. // if (notifyp)
  188. // {
  189. // notifyp->close();
  190. // }
  191. // mLoginNotificationHandle.markDead();
  192. //}
  193. break;
  194. case STATUS_LEFT_CHANNEL:
  195. if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
  196. {
  197. // if forceably removed from channel
  198. // update the UI and revert to default channel
  199. deactivate();
  200. }
  201. mIgnoreNextSessionLeave = FALSE;
  202. break;
  203. case STATUS_JOINING:
  204. if (callStarted())
  205. {
  206. setState(STATE_RINGING);
  207. }
  208. break;
  209. case STATUS_JOINED:
  210. if (callStarted())
  211. {
  212. setState(STATE_CONNECTED);
  213. }
  214. default:
  215. break;
  216. }
  217. }
  218. // default behavior is to just deactivate channel
  219. // derived classes provide specific error messages
  220. void LLVoiceChannel::handleError(EStatusType type)
  221. {
  222. deactivate();
  223. setState(STATE_ERROR);
  224. }
  225. BOOL LLVoiceChannel::isActive()
  226. {
  227. // only considered active when currently bound channel matches what our channel
  228. return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;
  229. }
  230. BOOL LLVoiceChannel::callStarted()
  231. {
  232. return mState >= STATE_CALL_STARTED;
  233. }
  234. void LLVoiceChannel::deactivate()
  235. {
  236. if (mState >= STATE_RINGING)
  237. {
  238. // ignore session leave event
  239. mIgnoreNextSessionLeave = TRUE;
  240. }
  241. if (callStarted())
  242. {
  243. setState(STATE_HUNG_UP);
  244. //Default mic is OFF when leaving voice calls
  245. if (gSavedSettings.getBOOL("AutoDisengageMic") &&
  246. sCurrentVoiceChannel == this &&
  247. LLVoiceClient::getInstance()->getUserPTTState())
  248. {
  249. gSavedSettings.setBOOL("PTTCurrentlyEnabled", true);
  250. LLVoiceClient::getInstance()->inputUserControlState(true);
  251. }
  252. }
  253. LLVoiceClient::getInstance()->removeObserver(this);
  254. if (sCurrentVoiceChannel == this)
  255. {
  256. // default channel is proximal channel
  257. sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
  258. sCurrentVoiceChannel->activate();
  259. }
  260. }
  261. void LLVoiceChannel::activate()
  262. {
  263. if (callStarted())
  264. {
  265. return;
  266. }
  267. // deactivate old channel and mark ourselves as the active one
  268. if (sCurrentVoiceChannel != this)
  269. {
  270. // mark as current before deactivating the old channel to prevent
  271. // activating the proximal channel between IM calls
  272. LLVoiceChannel* old_channel = sCurrentVoiceChannel;
  273. sCurrentVoiceChannel = this;
  274. mCallDialogPayload["old_channel_name"] = "";
  275. if (old_channel)
  276. {
  277. mCallDialogPayload["old_channel_name"] = old_channel->getSessionName();
  278. old_channel->deactivate();
  279. }
  280. }
  281. if (mState == STATE_NO_CHANNEL_INFO)
  282. {
  283. // responsible for setting status to active
  284. getChannelInfo();
  285. }
  286. else
  287. {
  288. setState(STATE_CALL_STARTED);
  289. }
  290. LLVoiceClient::getInstance()->addObserver(this);
  291. //do not send earlier, channel should be initialized, should not be in STATE_NO_CHANNEL_INFO state
  292. sCurrentVoiceChannelChangedSignal(this->mSessionID);
  293. }
  294. void LLVoiceChannel::getChannelInfo()
  295. {
  296. // pretend we have everything we need
  297. if (sCurrentVoiceChannel == this)
  298. {
  299. setState(STATE_CALL_STARTED);
  300. }
  301. }
  302. //static
  303. LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id)
  304. {
  305. voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id);
  306. if (found_it == sVoiceChannelMap.end())
  307. {
  308. return NULL;
  309. }
  310. else
  311. {
  312. return found_it->second;
  313. }
  314. }
  315. //static
  316. LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)
  317. {
  318. voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri);
  319. if (found_it == sVoiceChannelURIMap.end())
  320. {
  321. return NULL;
  322. }
  323. else
  324. {
  325. return found_it->second;
  326. }
  327. }
  328. LLVoiceChannel* LLVoiceChannel::getCurrentVoiceChannel()
  329. {
  330. return sCurrentVoiceChannel;
  331. }
  332. void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
  333. {
  334. sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
  335. mSessionID = new_session_id;
  336. sVoiceChannelMap.insert(std::make_pair(mSessionID, this));
  337. }
  338. void LLVoiceChannel::setURI(std::string uri)
  339. {
  340. sVoiceChannelURIMap.erase(mURI);
  341. mURI = uri;
  342. sVoiceChannelURIMap.insert(std::make_pair(mURI, this));
  343. }
  344. void LLVoiceChannel::setState(EState state)
  345. {
  346. switch(state)
  347. {
  348. case STATE_RINGING:
  349. //TODO: remove or redirect this call status notification
  350. // LLCallInfoDialog::show("ringing", mNotifyArgs);
  351. break;
  352. case STATE_CONNECTED:
  353. //TODO: remove or redirect this call status notification
  354. // LLCallInfoDialog::show("connected", mNotifyArgs);
  355. break;
  356. case STATE_HUNG_UP:
  357. //TODO: remove or redirect this call status notification
  358. // LLCallInfoDialog::show("hang_up", mNotifyArgs);
  359. break;
  360. default:
  361. break;
  362. }
  363. doSetState(state);
  364. }
  365. void LLVoiceChannel::doSetState(const EState& new_state)
  366. {
  367. EState old_state = mState;
  368. mState = new_state;
  369. if (!mStateChangedCallback.empty())
  370. mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent);
  371. }
  372. //static
  373. void LLVoiceChannel::initClass()
  374. {
  375. sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
  376. }
  377. //static
  378. void LLVoiceChannel::suspend()
  379. {
  380. if (!sSuspended)
  381. {
  382. sSuspendedVoiceChannel = sCurrentVoiceChannel;
  383. sSuspended = TRUE;
  384. }
  385. }
  386. //static
  387. void LLVoiceChannel::resume()
  388. {
  389. if (sSuspended)
  390. {
  391. if (LLVoiceClient::getInstance()->voiceEnabled())
  392. {
  393. if (sSuspendedVoiceChannel)
  394. {
  395. sSuspendedVoiceChannel->activate();
  396. }
  397. else
  398. {
  399. LLVoiceChannelProximal::getInstance()->activate();
  400. }
  401. }
  402. sSuspended = FALSE;
  403. }
  404. }
  405. boost::signals2::connection LLVoiceChannel::setCurrentVoiceChannelChangedCallback(channel_changed_callback_t cb, bool at_front)
  406. {
  407. if (at_front)
  408. {
  409. return sCurrentVoiceChannelChangedSignal.connect(cb, boost::signals2::at_front);
  410. }
  411. else
  412. {
  413. return sCurrentVoiceChannelChangedSignal.connect(cb);
  414. }
  415. }
  416. //
  417. // LLVoiceChannelGroup
  418. //
  419. LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :
  420. LLVoiceChannel(session_id, session_name)
  421. {
  422. mRetries = DEFAULT_RETRIES_COUNT;
  423. mIsRetrying = FALSE;
  424. }
  425. void LLVoiceChannelGroup::deactivate()
  426. {
  427. if (callStarted())
  428. {
  429. LLVoiceClient::getInstance()->leaveNonSpatialChannel();
  430. }
  431. LLVoiceChannel::deactivate();
  432. }
  433. void LLVoiceChannelGroup::activate()
  434. {
  435. if (callStarted()) return;
  436. LLVoiceChannel::activate();
  437. if (callStarted())
  438. {
  439. // we have the channel info, just need to use it now
  440. LLVoiceClient::getInstance()->setNonSpatialChannel(
  441. mURI,
  442. mCredentials);
  443. if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel
  444. {
  445. LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionID);
  446. // Adding ad-hoc call participants to Recent People List.
  447. // If it's an outgoing ad-hoc, we can use mInitialTargetIDs that holds IDs of people we
  448. // called(both online and offline) as source to get people for recent (STORM-210).
  449. if (session->isOutgoingAdHoc())
  450. {
  451. for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();
  452. it!=session->mInitialTargetIDs.end();++it)
  453. {
  454. const LLUUID id = *it;
  455. LLRecentPeople::instance().add(id);
  456. }
  457. }
  458. // If this ad-hoc is incoming then trying to get ids of people from mInitialTargetIDs
  459. // would lead to EXT-8246. So in this case we get them from speakers list.
  460. else
  461. {
  462. LLIMModel::addSpeakersToRecent(mSessionID);
  463. }
  464. }
  465. //Mic default state is OFF on initiating/joining Ad-Hoc/Group calls
  466. if (LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle())
  467. {
  468. LLVoiceClient::getInstance()->inputUserControlState(true);
  469. }
  470. }
  471. }
  472. void LLVoiceChannelGroup::getChannelInfo()
  473. {
  474. LLViewerRegion* region = gAgent.getRegion();
  475. if (region)
  476. {
  477. std::string url = region->getCapability("ChatSessionRequest");
  478. LLSD data;
  479. data["method"] = "call";
  480. data["session-id"] = mSessionID;
  481. LLHTTPClient::post(url,
  482. data,
  483. new LLVoiceCallCapResponder(mSessionID));
  484. }
  485. }
  486. void LLVoiceChannelGroup::setChannelInfo(
  487. const std::string& uri,
  488. const std::string& credentials)
  489. {
  490. setURI(uri);
  491. mCredentials = credentials;
  492. if (mState == STATE_NO_CHANNEL_INFO)
  493. {
  494. if(!mURI.empty() && !mCredentials.empty())
  495. {
  496. setState(STATE_READY);
  497. // if we are supposed to be active, reconnect
  498. // this will happen on initial connect, as we request credentials on first use
  499. if (sCurrentVoiceChannel == this)
  500. {
  501. // just in case we got new channel info while active
  502. // should move over to new channel
  503. activate();
  504. }
  505. }
  506. else
  507. {
  508. //*TODO: notify user
  509. LL_WARNS("Voice") << "Received invalid credentials for channel " << mSessionName << LL_ENDL;
  510. deactivate();
  511. }
  512. }
  513. else if ( mIsRetrying )
  514. {
  515. // we have the channel info, just need to use it now
  516. LLVoiceClient::getInstance()->setNonSpatialChannel(
  517. mURI,
  518. mCredentials);
  519. }
  520. }
  521. void LLVoiceChannelGroup::handleStatusChange(EStatusType type)
  522. {
  523. // status updates
  524. switch(type)
  525. {
  526. case STATUS_JOINED:
  527. mRetries = 3;
  528. mIsRetrying = FALSE;
  529. default:
  530. break;
  531. }
  532. LLVoiceChannel::handleStatusChange(type);
  533. }
  534. void LLVoiceChannelGroup::handleError(EStatusType status)
  535. {
  536. std::string notify;
  537. switch(status)
  538. {
  539. case ERROR_CHANNEL_LOCKED:
  540. case ERROR_CHANNEL_FULL:
  541. notify = "VoiceChannelFull";
  542. break;
  543. case ERROR_NOT_AVAILABLE:
  544. //clear URI and credentials
  545. //set the state to be no info
  546. //and activate
  547. if ( mRetries > 0 )
  548. {
  549. mRetries--;
  550. mIsRetrying = TRUE;
  551. mIgnoreNextSessionLeave = TRUE;
  552. getChannelInfo();
  553. return;
  554. }
  555. else
  556. {
  557. notify = "VoiceChannelJoinFailed";
  558. mRetries = DEFAULT_RETRIES_COUNT;
  559. mIsRetrying = FALSE;
  560. }
  561. break;
  562. case ERROR_UNKNOWN:
  563. default:
  564. break;
  565. }
  566. // notification
  567. if (!notify.empty())
  568. {
  569. LLNotificationPtr notification = LLNotificationsUtil::add(notify, mNotifyArgs);
  570. // echo to im window
  571. gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage());
  572. }
  573. LLVoiceChannel::handleError(status);
  574. }
  575. void LLVoiceChannelGroup::setState(EState state)
  576. {
  577. switch(state)
  578. {
  579. case STATE_RINGING:
  580. if ( !mIsRetrying )
  581. {
  582. //TODO: remove or redirect this call status notification
  583. // LLCallInfoDialog::show("ringing", mNotifyArgs);
  584. }
  585. doSetState(state);
  586. break;
  587. default:
  588. LLVoiceChannel::setState(state);
  589. }
  590. }
  591. //
  592. // LLVoiceChannelProximal
  593. //
  594. LLVoiceChannelProximal::LLVoiceChannelProximal() :
  595. LLVoiceChannel(LLUUID::null, LLStringUtil::null)
  596. {
  597. }
  598. BOOL LLVoiceChannelProximal::isActive()
  599. {
  600. return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();
  601. }
  602. void LLVoiceChannelProximal::activate()
  603. {
  604. if (callStarted()) return;
  605. if((LLVoiceChannel::sCurrentVoiceChannel != this) && (LLVoiceChannel::getState() == STATE_CONNECTED))
  606. {
  607. // we're connected to a non-spatial channel, so disconnect.
  608. LLVoiceClient::getInstance()->leaveNonSpatialChannel();
  609. }
  610. LLVoiceChannel::activate();
  611. }
  612. void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal)
  613. {
  614. if (!proximal)
  615. {
  616. return;
  617. }
  618. if (type < BEGIN_ERROR_STATUS)
  619. {
  620. handleStatusChange(type);
  621. }
  622. else
  623. {
  624. handleError(type);
  625. }
  626. }
  627. void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
  628. {
  629. // status updates
  630. switch(status)
  631. {
  632. case STATUS_LEFT_CHANNEL:
  633. // do not notify user when leaving proximal channel
  634. return;
  635. case STATUS_VOICE_DISABLED:
  636. //skip showing "Voice not available at your current location" when agent voice is disabled (EXT-4749)
  637. if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking())
  638. {
  639. //TODO: remove or redirect this call status notification
  640. // LLCallInfoDialog::show("unavailable", mNotifyArgs);
  641. }
  642. return;
  643. default:
  644. break;
  645. }
  646. LLVoiceChannel::handleStatusChange(status);
  647. }
  648. void LLVoiceChannelProximal::handleError(EStatusType status)
  649. {
  650. std::string notify;
  651. switch(status)
  652. {
  653. case ERROR_CHANNEL_LOCKED:
  654. case ERROR_CHANNEL_FULL:
  655. notify = "ProximalVoiceChannelFull";
  656. break;
  657. default:
  658. break;
  659. }
  660. // notification
  661. if (!notify.empty())
  662. {
  663. LLNotificationsUtil::add(notify, mNotifyArgs);
  664. }
  665. LLVoiceChannel::handleError(status);
  666. }
  667. void LLVoiceChannelProximal::deactivate()
  668. {
  669. if (callStarted())
  670. {
  671. setState(STATE_HUNG_UP);
  672. }
  673. }
  674. //
  675. // LLVoiceChannelP2P
  676. //
  677. LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :
  678. LLVoiceChannelGroup(session_id, session_name),
  679. mOtherUserID(other_user_id),
  680. mReceivedCall(FALSE)
  681. {
  682. // make sure URI reflects encoded version of other user's agent id
  683. // *NOTE: in case of Avaline call generated SIP URL will be incorrect.
  684. // But it will be overridden in LLVoiceChannelP2P::setSessionHandle() called when agent accepts call
  685. setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
  686. }
  687. void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
  688. {
  689. LL_INFOS("Voice") << "P2P CALL CHANNEL STATUS CHANGE: incoming=" << int(mReceivedCall) << " newstatus=" << LLVoiceClientStatusObserver::status2string(type) << " (mState=" << mState << ")" << LL_ENDL;
  690. // status updates
  691. switch(type)
  692. {
  693. case STATUS_LEFT_CHANNEL:
  694. if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
  695. {
  696. // *TODO: use it to show DECLINE voice notification
  697. if (mState == STATE_RINGING)
  698. {
  699. // other user declined call
  700. LLNotificationsUtil::add("P2PCallDeclined", mNotifyArgs);
  701. }
  702. else
  703. {
  704. // other user hung up, so we didn't end the call
  705. mCallEndedByAgent = false;
  706. }
  707. deactivate();
  708. }
  709. mIgnoreNextSessionLeave = FALSE;
  710. return;
  711. case STATUS_JOINING:
  712. // because we join session we expect to process session leave event in the future. EXT-7371
  713. // may be this should be done in the LLVoiceChannel::handleStatusChange.
  714. mIgnoreNextSessionLeave = FALSE;
  715. break;
  716. default:
  717. break;
  718. }
  719. LLVoiceChannel::handleStatusChange(type);
  720. }
  721. void LLVoiceChannelP2P::handleError(EStatusType type)
  722. {
  723. switch(type)
  724. {
  725. case ERROR_NOT_AVAILABLE:
  726. LLNotificationsUtil::add("P2PCallNoAnswer", mNotifyArgs);
  727. break;
  728. default:
  729. break;
  730. }
  731. LLVoiceChannel::handleError(type);
  732. }
  733. void LLVoiceChannelP2P::activate()
  734. {
  735. if (callStarted()) return;
  736. //call will be counted as ended by user unless this variable is changed in handleStatusChange()
  737. mCallEndedByAgent = true;
  738. LLVoiceChannel::activate();
  739. if (callStarted())
  740. {
  741. // no session handle yet, we're starting the call
  742. if (mSessionHandle.empty())
  743. {
  744. mReceivedCall = FALSE;
  745. LLVoiceClient::getInstance()->callUser(mOtherUserID);
  746. }
  747. // otherwise answering the call
  748. else
  749. {
  750. if (!LLVoiceClient::getInstance()->answerInvite(mSessionHandle))
  751. {
  752. mCallEndedByAgent = false;
  753. mSessionHandle.clear();
  754. handleError(ERROR_UNKNOWN);
  755. return;
  756. }
  757. // using the session handle invalidates it. Clear it out here so we can't reuse it by accident.
  758. mSessionHandle.clear();
  759. }
  760. // Add the party to the list of people with which we've recently interacted.
  761. addToTheRecentPeopleList();
  762. //Default mic is ON on initiating/joining P2P calls
  763. if (!LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle())
  764. {
  765. LLVoiceClient::getInstance()->inputUserControlState(true);
  766. }
  767. }
  768. }
  769. void LLVoiceChannelP2P::getChannelInfo()
  770. {
  771. // pretend we have everything we need, since P2P doesn't use channel info
  772. if (sCurrentVoiceChannel == this)
  773. {
  774. setState(STATE_CALL_STARTED);
  775. }
  776. }
  777. // receiving session from other user who initiated call
  778. void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI)
  779. {
  780. BOOL needs_activate = FALSE;
  781. if (callStarted())
  782. {
  783. // defer to lower agent id when already active
  784. if (mOtherUserID < gAgent.getID())
  785. {
  786. // pretend we haven't started the call yet, so we can connect to this session instead
  787. deactivate();
  788. needs_activate = TRUE;
  789. }
  790. else
  791. {
  792. // we are active and have priority, invite the other user again
  793. // under the assumption they will join this new session
  794. mSessionHandle.clear();
  795. LLVoiceClient::getInstance()->callUser(mOtherUserID);
  796. return;
  797. }
  798. }
  799. mSessionHandle = handle;
  800. // The URI of a p2p session should always be the other end's SIP URI.
  801. if(!inURI.empty())
  802. {
  803. setURI(inURI);
  804. }
  805. else
  806. {
  807. LL_WARNS("Voice") << "incoming SIP URL is not provided. Channel may not work properly." << LL_ENDL;
  808. // In the case of an incoming AvaLine call, the generated URI will be different from the
  809. // original one. This is because the P2P URI is based on avatar UUID but Avaline is not.
  810. // See LLVoiceClient::sessionAddedEvent()
  811. setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
  812. }
  813. mReceivedCall = TRUE;
  814. if (needs_activate)
  815. {
  816. activate();
  817. }
  818. }
  819. void LLVoiceChannelP2P::setState(EState state)
  820. {
  821. LL_INFOS("Voice") << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << LL_ENDL;
  822. if (mReceivedCall) // incoming call
  823. {
  824. // you only "answer" voice invites in p2p mode
  825. // so provide a special purpose message here
  826. if (mReceivedCall && state == STATE_RINGING)
  827. {
  828. //TODO: remove or redirect this call status notification
  829. // LLCallInfoDialog::show("answering", mNotifyArgs);
  830. doSetState(state);
  831. return;
  832. }
  833. }
  834. LLVoiceChannel::setState(state);
  835. }
  836. void LLVoiceChannelP2P::addToTheRecentPeopleList()
  837. {
  838. bool avaline_call = LLIMModel::getInstance()->findIMSession(mSessionID)->isAvalineSessionType();
  839. if (avaline_call)
  840. {
  841. LLSD call_data;
  842. std::string call_number = LLVoiceChannel::getSessionName();
  843. call_data["avaline_call"] = true;
  844. call_data["session_id"] = mSessionID;
  845. call_data["call_number"] = call_number;
  846. call_data["date"] = LLDate::now();
  847. LLRecentPeople::instance().add(mOtherUserID, call_data);
  848. }
  849. else
  850. {
  851. LLRecentPeople::instance().add(mOtherUserID);
  852. }
  853. }