llvoicechannel.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. /**
  2. * @file llvoicechannel.cpp
  3. * @brief Voice Channel related classes
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llvoicechannel.h"
  34. #include "llcachename.h"
  35. #include "llcorehttputil.h"
  36. #include "llnotifications.h"
  37. #include "llagent.h"
  38. #include "llcommandhandler.h"
  39. #include "llimmgr.h"
  40. #include "llmediactrl.h"
  41. #include "llviewercontrol.h"
  42. constexpr U32 DEFAULT_RETRIES_COUNT = 3;
  43. // Static variables
  44. LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
  45. LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
  46. LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
  47. bool LLVoiceChannel::sSuspended = false;
  48. ///////////////////////////////////////////////////////////////////////////////
  49. // Global command handler for voicecallavatar
  50. ///////////////////////////////////////////////////////////////////////////////
  51. class LLVoiceCallAvatarHandler final : public LLCommandHandler
  52. {
  53. public:
  54. LLVoiceCallAvatarHandler()
  55. : LLCommandHandler("voicecallavatar", UNTRUSTED_THROTTLE)
  56. {
  57. }
  58. bool handle(const LLSD& params, const LLSD&, LLMediaCtrl*) override
  59. {
  60. // Make sure we have some parameters
  61. if (params.size() == 0)
  62. {
  63. return false;
  64. }
  65. // Get the ID
  66. LLUUID id;
  67. if (!id.set(params[0], false))
  68. {
  69. return false;
  70. }
  71. std::string name;
  72. if (gIMMgrp && gCacheNamep && gCacheNamep->getFullName(id, name))
  73. {
  74. // Once the IM panel will be opened, and provided that both the
  75. // caller and the recipient are voice-enabled, the user will be
  76. // only one click away from an actual voice call...
  77. // When no voice is available, this action is still consistent
  78. // With the "Call" link it is associated with in web profiles.
  79. gIMMgrp->setFloaterOpen(true);
  80. gIMMgrp->addSession(name, IM_NOTHING_SPECIAL, id);
  81. make_ui_sound("UISndStartIM");
  82. }
  83. return true;
  84. }
  85. };
  86. LLVoiceCallAvatarHandler gVoiceCallAvatarHandler;
  87. ///////////////////////////////////////////////////////////////////////////////
  88. // LLVoiceChannel class
  89. ///////////////////////////////////////////////////////////////////////////////
  90. LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id,
  91. const std::string& session_name)
  92. : mSessionID(session_id),
  93. mState(STATE_NO_CHANNEL_INFO),
  94. mSessionName(session_name),
  95. mOutgoingCall(true), // Set to false if needed in setChannelInfo(). HB
  96. mIgnoreNextSessionLeave(false)
  97. {
  98. mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName;
  99. if (!sVoiceChannelMap.emplace(session_id, this).second)
  100. {
  101. // A voice channel already exists for this session id, so this instance
  102. // will be orphaned the end result should simply be the failure to make
  103. // voice calls
  104. llwarns << "Duplicate voice channels registered for session_id "
  105. << session_id << llendl;
  106. }
  107. }
  108. LLVoiceChannel::~LLVoiceChannel()
  109. {
  110. if (gVoiceClient.ready()) // Be sure to keep this !
  111. {
  112. gVoiceClient.removeObserver(this);
  113. }
  114. if (sSuspendedVoiceChannel == this)
  115. {
  116. sSuspendedVoiceChannel = NULL;
  117. }
  118. if (sCurrentVoiceChannel == this)
  119. {
  120. sCurrentVoiceChannel = NULL;
  121. }
  122. sVoiceChannelMap.erase(mSessionID);
  123. }
  124. void LLVoiceChannel::setChannelInfo(const LLSD& channel_info)
  125. {
  126. LL_DEBUGS("Voice") << "New channel info: " << channel_info << LL_ENDL;
  127. mChannelInfo = channel_info;
  128. // Possibly fix the call direction (defaulting to outgoing) based on
  129. // "incoming" presence which is set in LLIMMgr::inviteUserResponse(). HB
  130. if (mChannelInfo.has("incoming"))
  131. {
  132. mOutgoingCall = false;
  133. }
  134. if (mState == STATE_NO_CHANNEL_INFO)
  135. {
  136. if (mChannelInfo.isUndefined() || !mChannelInfo.isMap() ||
  137. !mChannelInfo.size())
  138. {
  139. gNotifications.add("VoiceChannelJoinFailed", mNotifyArgs);
  140. deactivate();
  141. }
  142. else
  143. {
  144. setState(STATE_READY);
  145. // If we are supposed to be active, reconnect. This will happen on
  146. // initial connect, as we request credentials on first use
  147. if (sCurrentVoiceChannel == this)
  148. {
  149. // Just in case we got new channel info while active should
  150. // move over to new channel.
  151. activate();
  152. }
  153. }
  154. }
  155. }
  156. void LLVoiceChannel::onChange(EStatusType type, const LLSD& channel_info, bool)
  157. {
  158. if (mChannelInfo.isUndefined() ||
  159. (mChannelInfo.isMap() && !mChannelInfo.size()))
  160. {
  161. LL_DEBUGS("Voice") << "New channel info: " << channel_info << LL_ENDL;
  162. mChannelInfo = channel_info;
  163. }
  164. else
  165. {
  166. LL_DEBUGS("Voice") << "Keeping current channel info: " << mChannelInfo
  167. << LL_ENDL;
  168. }
  169. if (gVoiceClient.compareChannels(mChannelInfo, channel_info))
  170. {
  171. if (type < BEGIN_ERROR_STATUS)
  172. {
  173. handleStatusChange(type);
  174. }
  175. else
  176. {
  177. handleError(type);
  178. }
  179. }
  180. }
  181. void LLVoiceChannel::handleStatusChange(EStatusType type)
  182. {
  183. switch (type)
  184. {
  185. case STATUS_LOGIN_RETRY:
  186. gNotifications.add("VoiceLoginRetry");
  187. break;
  188. case STATUS_LOGGED_IN:
  189. break;
  190. case STATUS_LEFT_CHANNEL:
  191. if (callStarted() && !sSuspended)
  192. {
  193. // If forcibly removed from channel update the UI and revert to
  194. // default channel.
  195. gNotifications.add("VoiceChannelDisconnected", mNotifyArgs);
  196. // This will set the State to STATE_HUNG_UP so when this method
  197. // is called again during shutdown callStarted() will return
  198. // false and this deactivate() would not be called again.
  199. deactivate();
  200. }
  201. break;
  202. case STATUS_JOINING:
  203. if (callStarted())
  204. {
  205. setState(STATE_RINGING);
  206. }
  207. break;
  208. case STATUS_JOINED:
  209. if (callStarted())
  210. {
  211. setState(STATE_CONNECTED);
  212. }
  213. default:
  214. break;
  215. }
  216. }
  217. // Default behavior is to just deactivate channel derived classes provide
  218. // specific error messages
  219. void LLVoiceChannel::handleError(EStatusType type)
  220. {
  221. deactivate();
  222. setState(STATE_ERROR);
  223. }
  224. bool LLVoiceChannel::isActive()
  225. {
  226. // Only considered active when currently bound channel matches what our
  227. // channel
  228. return callStarted() && gVoiceClient.isCurrentChannel(mChannelInfo);
  229. }
  230. void LLVoiceChannel::deactivate()
  231. {
  232. if (mState >= STATE_RINGING)
  233. {
  234. // Ignore session leave event
  235. mIgnoreNextSessionLeave = true;
  236. }
  237. if (callStarted())
  238. {
  239. setState(STATE_HUNG_UP);
  240. // Mute the microphone if required when returning to the proximal
  241. // channel
  242. if (sCurrentVoiceChannel == this && gVoiceClient.getUserPTTState() &&
  243. gSavedSettings.getBool("AutoDisengageMic"))
  244. {
  245. gSavedSettings.setBool("PTTCurrentlyEnabled", true);
  246. gVoiceClient.setUserPTTState(false);
  247. }
  248. }
  249. gVoiceClient.removeObserver(this);
  250. if (sCurrentVoiceChannel == this)
  251. {
  252. // Default channel is proximal channel
  253. sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
  254. sCurrentVoiceChannel->activate();
  255. }
  256. }
  257. void LLVoiceChannel::activate()
  258. {
  259. if (callStarted())
  260. {
  261. return;
  262. }
  263. // Deactivate old channel and mark ourselves as the active one
  264. if (sCurrentVoiceChannel != this)
  265. {
  266. // Mark as current before deactivating the old channel to prevent
  267. // activating the proximal channel between IM calls
  268. LLVoiceChannel* old_channelp = sCurrentVoiceChannel;
  269. sCurrentVoiceChannel = this;
  270. if (old_channelp)
  271. {
  272. old_channelp->deactivate();
  273. }
  274. }
  275. if (mState == STATE_NO_CHANNEL_INFO)
  276. {
  277. // Responsible for setting status to active
  278. requestChannelInfo();
  279. }
  280. else
  281. {
  282. setState(STATE_CALL_STARTED);
  283. }
  284. gVoiceClient.addObserver(this);
  285. }
  286. void LLVoiceChannel::requestChannelInfo()
  287. {
  288. // Pretend we have everything we need
  289. if (sCurrentVoiceChannel == this)
  290. {
  291. setState(STATE_CALL_STARTED);
  292. }
  293. }
  294. //static
  295. LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id)
  296. {
  297. voice_channel_map_t::iterator it = sVoiceChannelMap.find(session_id);
  298. return it != sVoiceChannelMap.end() ? it->second : NULL;
  299. }
  300. void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
  301. {
  302. sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
  303. mSessionID = new_session_id;
  304. sVoiceChannelMap.emplace(mSessionID, this);
  305. }
  306. void LLVoiceChannel::setState(EState state)
  307. {
  308. if (!gIMMgrp) return;
  309. switch (state)
  310. {
  311. case STATE_RINGING:
  312. gIMMgrp->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
  313. break;
  314. case STATE_CONNECTED:
  315. gIMMgrp->addSystemMessage(mSessionID, "connected", mNotifyArgs);
  316. break;
  317. case STATE_HUNG_UP:
  318. gIMMgrp->addSystemMessage(mSessionID, "hang_up", mNotifyArgs);
  319. break;
  320. default:
  321. break;
  322. }
  323. mState = state;
  324. }
  325. //static
  326. void LLVoiceChannel::initClass()
  327. {
  328. sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
  329. }
  330. //static
  331. void LLVoiceChannel::suspend()
  332. {
  333. if (!sSuspended)
  334. {
  335. sSuspendedVoiceChannel = sCurrentVoiceChannel;
  336. sSuspended = true;
  337. }
  338. }
  339. //static
  340. void LLVoiceChannel::resume()
  341. {
  342. if (sSuspended)
  343. {
  344. if (LLVoiceClient::voiceEnabled())
  345. {
  346. if (sSuspendedVoiceChannel)
  347. {
  348. if (sSuspendedVoiceChannel->callStarted())
  349. {
  350. // Should have channel data already, restart
  351. sSuspendedVoiceChannel->setState(STATE_READY);
  352. }
  353. // Note: would not do anything if call is already started...
  354. sSuspendedVoiceChannel->activate();
  355. }
  356. else
  357. {
  358. LLVoiceChannelProximal::getInstance()->activate();
  359. }
  360. }
  361. sSuspended = false;
  362. }
  363. }
  364. ///////////////////////////////////////////////////////////////////////////////
  365. // LLVoiceChannelGroup class
  366. ///////////////////////////////////////////////////////////////////////////////
  367. LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id,
  368. const std::string& session_name,
  369. bool is_p2p)
  370. : LLVoiceChannel(session_id, session_name),
  371. mIsP2P(is_p2p)
  372. {
  373. mRetries = DEFAULT_RETRIES_COUNT;
  374. mIsRetrying = false;
  375. }
  376. //virtual
  377. void LLVoiceChannelGroup::deactivate()
  378. {
  379. if (callStarted())
  380. {
  381. gVoiceClient.leaveNonSpatialChannel();
  382. }
  383. LLVoiceChannel::deactivate();
  384. if (mIsP2P)
  385. {
  386. // Void the channel info for P2P adhoc channels so that we request it
  387. // again, hence throwing up the connect dialogue on the other side.
  388. setState(STATE_NO_CHANNEL_INFO);
  389. }
  390. }
  391. //virtual
  392. void LLVoiceChannelGroup::activate()
  393. {
  394. if (callStarted()) return;
  395. LLVoiceChannel::activate();
  396. if (!callStarted())
  397. {
  398. return;
  399. }
  400. // We have the channel info, just need to use it now.
  401. gVoiceClient.setNonSpatialChannel(mChannelInfo, mIsP2P && mOutgoingCall,
  402. mIsP2P);
  403. // Mic default state is OFF on initiating/joining Ad-Hoc/Group calls while
  404. // it is on for P2P using the adhoc infra.
  405. gVoiceClient.setUserPTTState(mIsP2P);
  406. }
  407. //static
  408. void LLVoiceChannelGroup::voiceCallCapCoro(const std::string& url,
  409. LLUUID session_id)
  410. {
  411. LLSD data;
  412. data["method"] = "call";
  413. data["session-id"] = session_id;
  414. LLSD params;
  415. params["preferred_voice_server_type"] =
  416. gSavedSettings.getString("VoiceServerType");
  417. data["alt_params"] = params;
  418. LLCoreHttpUtil::HttpCoroutineAdapter adapter("voiceCallCapCoro");
  419. LLSD result = adapter.postAndSuspend(url, data);
  420. LLCore::HttpStatus status =
  421. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  422. // Verify that the channel is still open on server reply, and bail if not.
  423. LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id);
  424. if (!channelp)
  425. {
  426. llinfos << "Got reply for closed session Id: " << session_id
  427. << ". Ignored." << llendl;
  428. return;
  429. }
  430. if (!status)
  431. {
  432. if (status == gStatusForbidden)
  433. {
  434. // 403 == no ability
  435. gNotifications.add("VoiceNotAllowed", channelp->getNotifyArgs());
  436. }
  437. else
  438. {
  439. gNotifications.add("VoiceCallGenericError",
  440. channelp->getNotifyArgs());
  441. }
  442. channelp->deactivate();
  443. return;
  444. }
  445. result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
  446. for (LLSD::map_const_iterator iter = result.beginMap(),
  447. end = result.endMap();
  448. iter != end; ++iter)
  449. {
  450. llinfos << "Got " << iter->first << llendl;
  451. }
  452. channelp->setChannelInfo(result["voice_credentials"]);
  453. }
  454. //virtual
  455. void LLVoiceChannelGroup::requestChannelInfo()
  456. {
  457. const std::string& url = gAgent.getRegionCapability("ChatSessionRequest");
  458. if (url.empty())
  459. {
  460. return;
  461. }
  462. gCoros.launch("LLVoiceChannelGroup::voiceCallCapCoro",
  463. boost::bind(&LLVoiceChannelGroup::voiceCallCapCoro, url,
  464. mSessionID));
  465. }
  466. //virtual
  467. void LLVoiceChannelGroup::setChannelInfo(const LLSD& channel_info)
  468. {
  469. mChannelInfo = channel_info;
  470. // Possibly fix the call direction (defaulting to outgoing) based on
  471. // "incoming" presence which is set in LLIMMgr::inviteUserResponse(). HB
  472. if (mChannelInfo.has("incoming"))
  473. {
  474. mOutgoingCall = false;
  475. }
  476. if (mState == STATE_NO_CHANNEL_INFO)
  477. {
  478. if (mChannelInfo.isDefined() && mChannelInfo.isMap())
  479. {
  480. setState(STATE_READY);
  481. // If we are supposed to be active, reconnect. This will happen on
  482. // initial connect, as we request credentials on first use
  483. if (sCurrentVoiceChannel == this)
  484. {
  485. // Just in case we got new channel info while active should
  486. // move over to new channel
  487. activate();
  488. }
  489. }
  490. else
  491. {
  492. deactivate();
  493. }
  494. }
  495. else if (mIsRetrying)
  496. {
  497. // We have the channel info, just need to use it now
  498. gVoiceClient.setNonSpatialChannel(mChannelInfo, mOutgoingCall, mIsP2P);
  499. }
  500. }
  501. //virtual
  502. void LLVoiceChannelGroup::handleStatusChange(EStatusType type)
  503. {
  504. // Status updates
  505. if (type == STATUS_JOINED)
  506. {
  507. mRetries = 3;
  508. mIsRetrying = false;
  509. }
  510. LLVoiceChannel::handleStatusChange(type);
  511. }
  512. //virtual
  513. void LLVoiceChannelGroup::handleError(EStatusType status)
  514. {
  515. std::string notify;
  516. switch (status)
  517. {
  518. case ERROR_CHANNEL_LOCKED:
  519. case ERROR_CHANNEL_FULL:
  520. notify = "VoiceChannelFull";
  521. break;
  522. case ERROR_NOT_AVAILABLE:
  523. // Clear URI and credentials, set the state to be no info and
  524. // activate
  525. if (mRetries > 0)
  526. {
  527. --mRetries;
  528. mIsRetrying = true;
  529. mIgnoreNextSessionLeave = true;
  530. requestChannelInfo();
  531. return;
  532. }
  533. else
  534. {
  535. notify = "VoiceChannelJoinFailed";
  536. mRetries = DEFAULT_RETRIES_COUNT;
  537. mIsRetrying = false;
  538. }
  539. break;
  540. case ERROR_UNKNOWN:
  541. default:
  542. break;
  543. }
  544. // Notification
  545. if (!notify.empty())
  546. {
  547. LLNotificationPtr notifp = gNotifications.add(notify, mNotifyArgs);
  548. // Echo to IM window
  549. if (gIMMgrp)
  550. {
  551. gIMMgrp->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM,
  552. notifp->getMessage());
  553. }
  554. }
  555. LLVoiceChannel::handleError(status);
  556. }
  557. //virtual
  558. void LLVoiceChannelGroup::setState(EState state)
  559. {
  560. if (state == STATE_RINGING)
  561. {
  562. if (!mIsRetrying && gIMMgrp)
  563. {
  564. gIMMgrp->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
  565. }
  566. mState = state;
  567. }
  568. else
  569. {
  570. LLVoiceChannel::setState(state);
  571. }
  572. }
  573. ///////////////////////////////////////////////////////////////////////////////
  574. // LLVoiceChannelProximal class
  575. ///////////////////////////////////////////////////////////////////////////////
  576. LLVoiceChannelProximal::LLVoiceChannelProximal()
  577. : LLVoiceChannel(LLUUID::null, LLStringUtil::null)
  578. {
  579. activate();
  580. }
  581. //virtual
  582. bool LLVoiceChannelProximal::isActive()
  583. {
  584. return callStarted() && gVoiceClient.inProximalChannel();
  585. }
  586. #define LL_NEW_ACTIVATION_ORDER 1
  587. //virtual
  588. void LLVoiceChannelProximal::activate()
  589. {
  590. if (callStarted()) return;
  591. #if LL_NEW_ACTIVATION_ORDER
  592. if (sCurrentVoiceChannel != this && mState == STATE_CONNECTED)
  593. {
  594. // We are connected to a non-spatial channel, so disconnect.
  595. gVoiceClient.leaveNonSpatialChannel();
  596. }
  597. #endif
  598. gVoiceClient.activateSpatialChannel(true);
  599. LLVoiceChannel::activate();
  600. #if !LL_NEW_ACTIVATION_ORDER
  601. if (callStarted())
  602. {
  603. // This implicitly puts you back in the spatial channel
  604. gVoiceClient.leaveNonSpatialChannel();
  605. }
  606. #endif
  607. }
  608. //virtual
  609. void LLVoiceChannelProximal::onChange(EStatusType type, const LLSD&,
  610. bool proximal)
  611. {
  612. if (proximal)
  613. {
  614. if (type < BEGIN_ERROR_STATUS)
  615. {
  616. handleStatusChange(type);
  617. }
  618. else
  619. {
  620. handleError(type);
  621. }
  622. }
  623. }
  624. //virtual
  625. void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
  626. {
  627. if (status == STATUS_LEFT_CHANNEL)
  628. {
  629. // Do not notify user when leaving proximal channel
  630. return;
  631. }
  632. if (status == STATUS_VOICE_DISABLED)
  633. {
  634. gVoiceClient.setUserPTTState(false);
  635. if (gIMMgrp)
  636. {
  637. gIMMgrp->addSystemMessage(LLUUID::null, "unavailable",
  638. mNotifyArgs);
  639. }
  640. return;
  641. }
  642. LLVoiceChannel::handleStatusChange(status);
  643. }
  644. //virtual
  645. void LLVoiceChannelProximal::handleError(EStatusType status)
  646. {
  647. if (status == ERROR_CHANNEL_LOCKED || status == ERROR_CHANNEL_FULL)
  648. {
  649. gNotifications.add("ProximalVoiceChannelFull", mNotifyArgs);
  650. }
  651. #if 0 // Proximal voice remains up and the provider will try to reconnect.
  652. LLVoiceChannel::handleError(status);
  653. #endif
  654. }
  655. //virtual
  656. void LLVoiceChannelProximal::deactivate()
  657. {
  658. if (callStarted())
  659. {
  660. setState(STATE_HUNG_UP);
  661. }
  662. gVoiceClient.removeObserver(this);
  663. gVoiceClient.activateSpatialChannel(false);
  664. }
  665. ///////////////////////////////////////////////////////////////////////////////
  666. // LLVoiceChannelP2P class
  667. ///////////////////////////////////////////////////////////////////////////////
  668. LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id,
  669. const std::string& session_name,
  670. const LLUUID& other_user_id,
  671. U32 server_type)
  672. : LLVoiceChannelGroup(session_id, session_name, true),
  673. mOtherUserID(other_user_id),
  674. mVoiceServerType(server_type),
  675. mReceivedCall(false),
  676. mVivoxIncomingCall(false)
  677. {
  678. }
  679. //virtual
  680. void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
  681. {
  682. if (type == STATUS_LEFT_CHANNEL)
  683. {
  684. if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
  685. {
  686. if (mState == STATE_RINGING)
  687. {
  688. // Other user declined call
  689. gNotifications.add("P2PCallDeclined", mNotifyArgs);
  690. }
  691. else
  692. {
  693. // Other user hung up
  694. gNotifications.add("VoiceChannelDisconnectedP2P", mNotifyArgs);
  695. }
  696. deactivate();
  697. }
  698. mIgnoreNextSessionLeave = false;
  699. return;
  700. }
  701. if (type == STATUS_JOINING)
  702. {
  703. // Because we join session we expect to process session leave event in
  704. // the future.
  705. mIgnoreNextSessionLeave = false;
  706. }
  707. LLVoiceChannel::handleStatusChange(type);
  708. }
  709. //virtual
  710. void LLVoiceChannelP2P::handleError(EStatusType type)
  711. {
  712. if (type == ERROR_NOT_AVAILABLE)
  713. {
  714. gNotifications.add("P2PCallNoAnswer", mNotifyArgs);
  715. }
  716. LLVoiceChannel::handleError(type);
  717. }
  718. //virtual
  719. void LLVoiceChannelP2P::activate()
  720. {
  721. if (callStarted()) return;
  722. LLVoiceChannel::activate();
  723. if (!callStarted())
  724. {
  725. return; // Nothing to do for now.
  726. }
  727. if (mVivoxIncomingCall)
  728. {
  729. // Answer the call
  730. mVivoxIncomingCall = false;
  731. if (!gVoiceClient.answerInvite(mChannelInfo))
  732. {
  733. handleError(ERROR_UNKNOWN);
  734. }
  735. }
  736. else
  737. // No session yet, we are starting the call
  738. {
  739. mReceivedCall = false;
  740. gVoiceClient.callUser(mOtherUserID, mVoiceServerType);
  741. }
  742. // Default mic is ON on initiating/joining P2P calls
  743. if (!gVoiceClient.getUserPTTState() && gVoiceClient.getPTTIsToggle())
  744. {
  745. gVoiceClient.inputUserControlState(true);
  746. }
  747. }
  748. //virtual
  749. void LLVoiceChannelP2P::deactivate()
  750. {
  751. if (callStarted())
  752. {
  753. gVoiceClient.hangup(mVoiceServerType);
  754. }
  755. LLVoiceChannel::deactivate();
  756. }
  757. //virtual
  758. void LLVoiceChannelP2P::requestChannelInfo()
  759. {
  760. // Pretend we have everything we need, since P2P does not use channel info.
  761. if (sCurrentVoiceChannel == this)
  762. {
  763. setState(STATE_CALL_STARTED);
  764. }
  765. }
  766. // Receiving session from other user who initiated call
  767. //virtual
  768. void LLVoiceChannelP2P::setChannelInfo(const LLSD& channel_info)
  769. {
  770. mChannelInfo = channel_info;
  771. // Possibly fix the call direction (defaulting to outgoing) based on
  772. // "incoming" presence which is set in LLIMMgr::inviteUserResponse(). HB
  773. if (mChannelInfo.has("incoming"))
  774. {
  775. mOutgoingCall = false;
  776. }
  777. bool needs_activate = false;
  778. if (callStarted())
  779. {
  780. // Defer to lower agent id when already active
  781. if (mOtherUserID < gAgentID)
  782. {
  783. // Pretend we have not started the call yet, so we can connect to
  784. // this session instead
  785. deactivate();
  786. needs_activate = true;
  787. }
  788. else
  789. {
  790. // We are active and have priority, invite the other user again
  791. // under the assumption they will join this new session
  792. gVoiceClient.callUser(mOtherUserID, mVoiceServerType);
  793. return;
  794. }
  795. }
  796. mReceivedCall = true;
  797. if (channel_info.isDefined() && channel_info.isMap() &&
  798. gVoiceClient.getVoiceServerType(channel_info) ==
  799. LLVoiceClient::VIVOX_SERVER)
  800. {
  801. mVivoxIncomingCall = true; // This is an incoming Vivox call.
  802. }
  803. if (needs_activate)
  804. {
  805. activate();
  806. }
  807. }
  808. //virtual
  809. void LLVoiceChannelP2P::setState(EState state)
  810. {
  811. // You only "answer" voice invites in P2P mode so provide a special purpose
  812. // message here
  813. if (mReceivedCall && state == STATE_RINGING)
  814. {
  815. if (gIMMgrp)
  816. {
  817. gIMMgrp->addSystemMessage(mSessionID, "answering", mNotifyArgs);
  818. }
  819. mState = state;
  820. return;
  821. }
  822. LLVoiceChannel::setState(state);
  823. }