llviewermedia.cpp 106 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312
  1. /**
  2. * @file llviewermedia.cpp
  3. * @brief Client interface to the media engine
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewergpl$
  6. *
  7. * Copyright (c) 2007-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. // "error: 'get_temporary_buffer<...>' is deprecated" seen with clang 18 and
  34. // gcc 12.3 libstdc++ implementation of std::stable_sort(). HB
  35. #if CLANG_VERSION >= 180000
  36. # pragma clang diagnostic ignored "-Wdeprecated-declarations"
  37. #endif
  38. #include <regex>
  39. #include "boost/signals2.hpp"
  40. #include "cef/dullahan.h" // For HB_DULLAHAN_EXTENDED
  41. #include "llviewermedia.h"
  42. #include "llcallbacklist.h"
  43. #include "lldir.h"
  44. #include "lldiriterator.h"
  45. #include "llfasttimer.h"
  46. #include "hbfileselector.h"
  47. #include "hbfloateruserauth.h"
  48. #include "llimagegl.h"
  49. #include "llkeyboard.h"
  50. #include "llmediaentry.h"
  51. #include "llmimetypes.h"
  52. #include "llparcel.h"
  53. #include "llsdserialize.h"
  54. #include "llversionviewer.h"
  55. #include "llview.h"
  56. #include "llagent.h"
  57. #include "llappviewer.h"
  58. #include "llfloateravatarinfo.h" // for getProfileURL()
  59. #include "slfloatermediafilter.h"
  60. #include "llhoverview.h"
  61. #include "llmutelist.h"
  62. #include "llstartup.h" // for getStartupState()
  63. #include "llurldispatcher.h"
  64. #include "llviewercontrol.h"
  65. #include "llviewermediafocus.h"
  66. #include "llviewerparcelmedia.h"
  67. #include "llviewerparcelmgr.h"
  68. #include "llviewerregion.h"
  69. #include "llviewertexturelist.h"
  70. #include "llviewerwindow.h"
  71. #include "llvoavatarself.h"
  72. #include "llvovolume.h"
  73. #include "llweb.h"
  74. // Move this to its own file.
  75. LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter()
  76. {
  77. observerListType::iterator iter = mObservers.begin();
  78. while (iter != mObservers.end())
  79. {
  80. LLViewerMediaObserver* self = *iter++;
  81. remObserver(self);
  82. }
  83. }
  84. bool LLViewerMediaEventEmitter::addObserver(LLViewerMediaObserver* observer)
  85. {
  86. if (!observer ||
  87. std::find(mObservers.begin(), mObservers.end(),
  88. observer) != mObservers.end())
  89. {
  90. return false;
  91. }
  92. mObservers.push_back(observer);
  93. observer->mEmitters.push_back(this);
  94. return true;
  95. }
  96. bool LLViewerMediaEventEmitter::remObserver(LLViewerMediaObserver* observer)
  97. {
  98. if (!observer)
  99. {
  100. return false;
  101. }
  102. mObservers.remove(observer);
  103. observer->mEmitters.remove(this);
  104. return true;
  105. }
  106. void LLViewerMediaEventEmitter::emitEvent(LLPluginClassMedia* media,
  107. LLPluginClassMediaOwner::EMediaEvent event)
  108. {
  109. // Broadcast the event to any observers.
  110. observerListType::iterator iter = mObservers.begin();
  111. while (iter != mObservers.end())
  112. {
  113. LLViewerMediaObserver* self = *iter++;
  114. self->handleMediaEvent(media, event);
  115. }
  116. }
  117. // Move this to its own file.
  118. LLViewerMediaObserver::~LLViewerMediaObserver()
  119. {
  120. std::list<LLViewerMediaEventEmitter*>::iterator iter = mEmitters.begin();
  121. while (iter != mEmitters.end())
  122. {
  123. LLViewerMediaEventEmitter* self = *iter++;
  124. self->remObserver(this);
  125. }
  126. }
  127. std::string LLViewerMedia::sOpenIDCookie;
  128. static LLViewerMedia::impl_list sViewerMediaImplList;
  129. typedef fast_hmap<LLUUID, LLViewerMediaImpl*> impl_id_map_t;
  130. static impl_id_map_t sViewerMediaTextureIDMap;
  131. static LLTimer sMediaCreateTimer;
  132. constexpr F32 LLVIEWERMEDIA_CREATE_DELAY = 1.f;
  133. static F32 sGlobalVolume = 1.f;
  134. static bool sForceUpdate = false;
  135. static LLUUID sOnlyAudibleTextureID;
  136. static F64 sLowestLoadableImplInterest = 0.0;
  137. bool LLViewerMedia::sAnyMediaShowing = false;
  138. bool LLViewerMedia::sAnyMediaEnabled = false;
  139. bool LLViewerMedia::sAnyMediaDisabled = false;
  140. static boost::signals2::connection sTeleportFinishConnection;
  141. // For the media filter implementation:
  142. bool LLViewerMedia::sIsUserAction = false;
  143. bool LLViewerMedia::sMediaFilterListLoaded = false;
  144. LLSD LLViewerMedia::sMediaFilterList;
  145. std::set<std::string> LLViewerMedia::sMediaQueries;
  146. std::set<std::string> LLViewerMedia::sAllowedMedia;
  147. std::set<std::string> LLViewerMedia::sDeniedMedia;
  148. std::map<std::string, std::string> LLViewerMedia::sDNSlookups;
  149. static void add_media_impl(LLViewerMediaImpl* media)
  150. {
  151. sViewerMediaImplList.push_back(media);
  152. }
  153. static void remove_media_impl(LLViewerMediaImpl* media)
  154. {
  155. for (LLViewerMedia::impl_list::iterator
  156. iter = sViewerMediaImplList.begin(),
  157. end = sViewerMediaImplList.end();
  158. iter != end; ++iter)
  159. {
  160. if (media == *iter)
  161. {
  162. sViewerMediaImplList.erase(iter);
  163. return;
  164. }
  165. }
  166. }
  167. static bool is_media_impl_valid(LLViewerMediaImpl* media)
  168. {
  169. if (!media) return false;
  170. LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end();
  171. return std::find(sViewerMediaImplList.begin(), end, media) != end;
  172. }
  173. class LLViewerMediaMuteListObserver final : public LLMuteListObserver
  174. {
  175. void onChange() override
  176. {
  177. LLViewerMedia::muteListChanged();
  178. }
  179. };
  180. static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver;
  181. static bool sViewerMediaMuteListObserverInitialized = false;
  182. ///////////////////////////////////////////////////////////////////////////////
  183. // LLViewerMedia
  184. ///////////////////////////////////////////////////////////////////////////////
  185. //static
  186. viewer_media_t LLViewerMedia::newMediaImpl(const LLUUID& texture_id,
  187. S32 media_width,
  188. S32 media_height,
  189. bool media_auto_scale,
  190. bool media_loop)
  191. {
  192. LLViewerMediaImpl* self = getMediaImplFromTextureID(texture_id);
  193. if (!self || texture_id.isNull())
  194. {
  195. // Create the media impl
  196. self = new LLViewerMediaImpl(texture_id, media_width, media_height,
  197. media_auto_scale, media_loop);
  198. }
  199. else
  200. {
  201. self->unload();
  202. self->setTextureID(texture_id);
  203. self->mMediaWidth = media_width;
  204. self->mMediaHeight = media_height;
  205. self->mMediaAutoScale = media_auto_scale;
  206. self->mMediaLoop = media_loop;
  207. }
  208. return self;
  209. }
  210. //static
  211. viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry,
  212. const std::string& previous_url,
  213. bool update_from_self)
  214. {
  215. // Try to find media with the same media ID
  216. viewer_media_t self = getMediaImplFromTextureID(media_entry->getMediaID());
  217. LL_DEBUGS("Media") << "called, current URL is \""
  218. << media_entry->getCurrentURL()
  219. << "\", previous URL is \"" << previous_url
  220. << "\", update_from_self is "
  221. << (update_from_self ? "true" : "false") << LL_ENDL;
  222. bool was_loaded = false;
  223. bool needs_navigate = false;
  224. if (self)
  225. {
  226. was_loaded = self->hasMedia();
  227. self->setHomeURL(media_entry->getHomeURL());
  228. self->mMediaAutoScale = media_entry->getAutoScale();
  229. self->mMediaLoop = media_entry->getAutoLoop();
  230. self->mMediaWidth = media_entry->getWidthPixels();
  231. self->mMediaHeight = media_entry->getHeightPixels();
  232. self->mMediaAutoPlay = media_entry->getAutoPlay();
  233. self->mMediaEntryURL = media_entry->getCurrentURL();
  234. if (self->mMediaSource)
  235. {
  236. self->mMediaSource->setAutoScale(self->mMediaAutoScale);
  237. self->mMediaSource->setLoop(self->mMediaLoop);
  238. self->mMediaSource->setSize(media_entry->getWidthPixels(),
  239. media_entry->getHeightPixels());
  240. }
  241. bool url_changed = self->mMediaEntryURL != previous_url;
  242. if (self->mMediaEntryURL.empty())
  243. {
  244. if (url_changed)
  245. {
  246. // The current media URL is now empty. Unload the media source.
  247. self->unload();
  248. LL_DEBUGS("Media") << "Unloading media instance (new current URL is empty)."
  249. << LL_ENDL;
  250. }
  251. }
  252. else
  253. {
  254. // The current media URL is not empty. If (the media was already
  255. // loaded OR the media was set to autoplay) AND this update did not
  256. // come from this agent, then do a navigate.
  257. bool auto_play = self->isAutoPlayable();
  258. if ((was_loaded || auto_play) && !update_from_self)
  259. {
  260. needs_navigate = url_changed;
  261. }
  262. LL_DEBUGS("Media") << "was_loaded is "
  263. << (was_loaded ? "true" : "false")
  264. << ", auto_play is "
  265. << (auto_play ? "true" : "false")
  266. << ", needs_navigate is "
  267. << (needs_navigate ? "true" : "false")
  268. << LL_ENDL;
  269. }
  270. }
  271. else
  272. {
  273. self = newMediaImpl(media_entry->getMediaID(),
  274. media_entry->getWidthPixels(),
  275. media_entry->getHeightPixels(),
  276. media_entry->getAutoScale(),
  277. media_entry->getAutoLoop());
  278. self->setHomeURL(media_entry->getHomeURL());
  279. self->mMediaAutoPlay = media_entry->getAutoPlay();
  280. self->mMediaEntryURL = media_entry->getCurrentURL();
  281. if (self->isAutoPlayable())
  282. {
  283. needs_navigate = true;
  284. }
  285. }
  286. if (self)
  287. {
  288. if (needs_navigate)
  289. {
  290. self->navigateTo(self->mMediaEntryURL, "", true, true);
  291. LL_DEBUGS("Media") << "Navigating to URL " << self->mMediaEntryURL
  292. << LL_ENDL;
  293. }
  294. else if (!self->mMediaURL.empty() &&
  295. self->mMediaURL != self->mMediaEntryURL)
  296. {
  297. // If we already have a non-empty media URL set and we are not
  298. // doing a navigate, update the media URL to match the media entry.
  299. self->mMediaURL = self->mMediaEntryURL;
  300. // If this causes a navigate at some point (such as after a
  301. // reload), it should be considered server-driven so it is not
  302. // broadcast.
  303. self->mNavigateServerRequest = true;
  304. LL_DEBUGS("Media") << "Updating URL in the media impl to "
  305. << self->mMediaEntryURL << LL_ENDL;
  306. }
  307. }
  308. return self;
  309. }
  310. //static
  311. LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id)
  312. {
  313. LLViewerMediaImpl* result = NULL;
  314. // Look up the texture ID in the texture id->impl map.
  315. impl_id_map_t::iterator iter = sViewerMediaTextureIDMap.find(texture_id);
  316. if (iter != sViewerMediaTextureIDMap.end())
  317. {
  318. result = iter->second;
  319. }
  320. return result;
  321. }
  322. //static
  323. LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureEntry(const LLTextureEntry* tep)
  324. {
  325. if (!tep) return NULL;
  326. LLUUID tid;
  327. LLMediaEntry* mep = tep->hasMedia() ? tep->getMediaData() : NULL;
  328. if (mep)
  329. {
  330. tid = mep->getMediaID();
  331. }
  332. else
  333. {
  334. // Parcel media do not have media data, but they nonetheless got a
  335. // media implement...
  336. tid = tep->getID();
  337. }
  338. return LLViewerMedia::getMediaImplFromTextureID(tid);
  339. }
  340. //static
  341. std::string LLViewerMedia::getCurrentUserAgent()
  342. {
  343. // Append our magic version number string to the browser user agent Id.
  344. // See the HTTP 1.0 and 1.1 specifications for allowed formats:
  345. // http://www.ietf.org/rfc/rfc1945.txt section 10.15
  346. // http://www.ietf.org/rfc/rfc2068.txt section 3.8
  347. // This was also helpful:
  348. // http://www.mozilla.org/build/revised-user-agent-strings.html
  349. std::ostringstream ua;
  350. ua << "SecondLife/"
  351. << LL_VERSION_MAJOR << "." << LL_VERSION_MINOR << "."
  352. << LL_VERSION_BRANCH << "." << LL_VERSION_RELEASE << " ("
  353. << gSavedSettings.getString("VersionChannelName") << "; "
  354. << gSavedSettings.getString("SkinCurrent") << " skin)";
  355. llinfos << "User agent: " << ua.str() << llendl;
  356. return ua.str();
  357. }
  358. //static
  359. bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id)
  360. {
  361. for (impl_list::iterator iter = sViewerMediaImplList.begin(),
  362. end = sViewerMediaImplList.end();
  363. iter != end; ++iter)
  364. {
  365. LLViewerMediaImpl* pimpl = *iter;
  366. if (pimpl->getMediaTextureID() == texture_id)
  367. {
  368. return true;
  369. }
  370. }
  371. return false;
  372. }
  373. //static
  374. void LLViewerMedia::setVolume(F32 volume)
  375. {
  376. if (volume != sGlobalVolume || sForceUpdate)
  377. {
  378. sGlobalVolume = volume;
  379. for (impl_list::iterator iter = sViewerMediaImplList.begin(),
  380. end = sViewerMediaImplList.end();
  381. iter != end; ++iter)
  382. {
  383. LLViewerMediaImpl* pimpl = *iter;
  384. pimpl->updateVolume();
  385. }
  386. sForceUpdate = false;
  387. }
  388. }
  389. //static
  390. F32 LLViewerMedia::getVolume()
  391. {
  392. return sGlobalVolume;
  393. }
  394. //static
  395. void LLViewerMedia::muteListChanged()
  396. {
  397. // When the mute list changes, we need to check mute status on all impls.
  398. for (impl_list::iterator iter = sViewerMediaImplList.begin(),
  399. end = sViewerMediaImplList.end();
  400. iter != end; iter++)
  401. {
  402. LLViewerMediaImpl* pimpl = *iter;
  403. pimpl->mNeedsMuteCheck = true;
  404. }
  405. }
  406. //static
  407. bool LLViewerMedia::isInterestingEnough(const LLVOVolume* object,
  408. F64 object_interest)
  409. {
  410. bool result = false;
  411. if (!object)
  412. {
  413. result = false;
  414. }
  415. // Focused ? Then it is interesting !
  416. else if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == object->getID())
  417. {
  418. result = true;
  419. }
  420. // Selected ? Then it is interesting !
  421. // XXX Sadly, 'contains()' does not take a const :(
  422. else if (gSelectMgr.getSelection()->contains(const_cast<LLVOVolume*>(object)))
  423. {
  424. result = true;
  425. }
  426. else
  427. {
  428. LL_DEBUGS("Media") << "object interest = " << object_interest
  429. << ", lowest loadable = "
  430. << sLowestLoadableImplInterest << LL_ENDL;
  431. if (object_interest >= sLowestLoadableImplInterest)
  432. {
  433. result = true;
  434. }
  435. }
  436. return result;
  437. }
  438. LLViewerMedia::impl_list& LLViewerMedia::getPriorityList()
  439. {
  440. return sViewerMediaImplList;
  441. }
  442. // This is the predicate function used to sort sViewerMediaImplList by
  443. // priority.
  444. bool LLViewerMedia::priorityComparator(const LLViewerMediaImpl* i1,
  445. const LLViewerMediaImpl* i2)
  446. {
  447. if (i1->isForcedUnloaded() && !i2->isForcedUnloaded())
  448. {
  449. // Muted or failed items always go to the end of the list, period.
  450. return false;
  451. }
  452. if (i2->isForcedUnloaded() && !i1->isForcedUnloaded())
  453. {
  454. // Muted or failed items always go to the end of the list, period.
  455. return true;
  456. }
  457. if (i1->hasFocus())
  458. {
  459. // The item with user focus always comes to the front of the list,
  460. // period.
  461. return true;
  462. }
  463. if (i2->hasFocus())
  464. {
  465. // The item with user focus always comes to the front of the list,
  466. // period.
  467. return false;
  468. }
  469. if (i1->isParcelMedia())
  470. {
  471. // The parcel media impl sorts above all other inworld media, unless
  472. // one has focus.
  473. return true;
  474. }
  475. if (i2->isParcelMedia())
  476. {
  477. // The parcel media impl sorts above all other inworld media, unless
  478. // one has focus.
  479. return false;
  480. }
  481. if (i1->getUsedInUI() && !i2->getUsedInUI())
  482. {
  483. // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it
  484. // sorts earlier in our list.
  485. return true;
  486. }
  487. if (i2->getUsedInUI() && !i1->getUsedInUI())
  488. {
  489. // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it
  490. // sorts earlier in our list.
  491. return false;
  492. }
  493. if (i1->getUsedOnHUD() && !i2->getUsedOnHUD())
  494. {
  495. // i1 is used on a HUD, i2 is not. This makes i1 "less than" i2, so it
  496. // sorts earlier in our list.
  497. return true;
  498. }
  499. if (i2->getUsedOnHUD() && !i1->getUsedOnHUD())
  500. {
  501. // i2 is used on a HUD, i1 is not. This makes i2 "less than" i1, so it
  502. // sorts earlier in our list.
  503. return false;
  504. }
  505. if (i1->isPlayable() && !i2->isPlayable())
  506. {
  507. // Playable items sort above ones that would not play even if they got
  508. // high enough priority
  509. return true;
  510. }
  511. if (!i1->isPlayable() && i2->isPlayable())
  512. {
  513. // Playable items sort above ones that would not play even if they got
  514. // high enough priority
  515. return false;
  516. }
  517. if (i1->getInterest() == i2->getInterest())
  518. {
  519. // Generally this will mean both objects have zero interest. In this
  520. // case, sort on distance.
  521. return i1->getProximityDistance() < i2->getProximityDistance();
  522. }
  523. // The object with the larger interest value should be earlier in the list,
  524. // so we reverse the sense of the comparison here.
  525. return i1->getInterest() > i2->getInterest();
  526. }
  527. static bool proximity_comparator(const LLViewerMediaImpl* i1,
  528. const LLViewerMediaImpl* i2)
  529. {
  530. if (i1->getProximityDistance() < i2->getProximityDistance())
  531. {
  532. return true;
  533. }
  534. if (i1->getProximityDistance() > i2->getProximityDistance())
  535. {
  536. return false;
  537. }
  538. // Both objects have the same distance. This most likely means they are two
  539. // faces of the same object. They may also be faces on different objects
  540. // with exactly the same distance (like HUD objects). We do not actually
  541. // care what the sort order is for this case, as long as it is stable and
  542. // does not change when you enable/disable media. Comparing the impl
  543. // pointers gives a completely arbitrary ordering, but it will be stable.
  544. return i1 < i2;
  545. }
  546. //static
  547. void LLViewerMedia::updateMedia(void*)
  548. {
  549. LL_FAST_TIMER(FTM_MEDIA_UPDATE);
  550. if (gDisconnected || LLApp::isExiting())
  551. {
  552. setAllMediaEnabled(false);
  553. return;
  554. }
  555. // Enable/disable the plugin read thread
  556. static LLCachedControl<bool> plugin_use_read_thread(gSavedSettings,
  557. "PluginUseReadThread");
  558. LLPluginProcessParent::setUseReadThread(plugin_use_read_thread);
  559. impl_list::iterator iter = sViewerMediaImplList.begin();
  560. impl_list::iterator end = sViewerMediaImplList.end();
  561. sAnyMediaShowing = sAnyMediaEnabled = sAnyMediaDisabled = false;
  562. {
  563. LL_FAST_TIMER(FTM_MEDIA_UPDATE_INTEREST);
  564. while (iter != end)
  565. {
  566. LLViewerMediaImpl* pimpl = *iter++;
  567. pimpl->update();
  568. pimpl->calculateInterest();
  569. }
  570. }
  571. {
  572. LL_FAST_TIMER(FTM_MEDIA_SORT);
  573. // Sort the static instance list using our interest criteria
  574. sViewerMediaImplList.sort(priorityComparator);
  575. }
  576. // Go through the list again and adjust according to priority.
  577. iter = sViewerMediaImplList.begin();
  578. end = sViewerMediaImplList.end();
  579. F64 total_cpu = 0.0;
  580. U32 impl_count_total = 0;
  581. U32 impl_count_interest_low = 0;
  582. U32 impl_count_interest_normal = 0;
  583. std::vector<LLViewerMediaImpl*> proximity_order;
  584. static LLCachedControl<bool> inworld_media_enabled(gSavedSettings,
  585. "EnableStreamingMedia");
  586. static LLCachedControl<bool> inworld_audio_enabled(gSavedSettings,
  587. "EnableStreamingMusic");
  588. static LLCachedControl<U32> max_instances(gSavedSettings,
  589. "PluginInstancesTotal");
  590. static LLCachedControl<U32> max_normal(gSavedSettings,
  591. "PluginInstancesNormal");
  592. static LLCachedControl<U32> max_low(gSavedSettings, "PluginInstancesLow");
  593. static LLCachedControl<F32> max_cpu(gSavedSettings,
  594. "PluginInstancesCPULimit");
  595. // Setting max_cpu to 0.0 disables CPU usage checking.
  596. bool check_cpu_usage = max_cpu != 0.f;
  597. LLViewerMediaImpl* lowest_interest_loadable = NULL;
  598. // Notes on tweakable params:
  599. // max_instances must be set high enough to allow the various instances
  600. // Used in the UI (for the help browser, search, etc) to be loaded. If
  601. // max_normal + max_low is less than max_instances, things will tend to get
  602. // unloaded instead of being set to slideshow.
  603. {
  604. LL_FAST_TIMER(FTM_MEDIA_MISC);
  605. LLPluginClassMedia::EPriority new_priority;
  606. for ( ; iter != end; ++iter)
  607. {
  608. LLViewerMediaImpl* pimpl = *iter;
  609. new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
  610. if (pimpl->isForcedUnloaded() || impl_count_total >= max_instances)
  611. {
  612. // Never load muted or failed impls. Hard limit on the number
  613. // of instances that will be loaded at one time
  614. new_priority = LLPluginClassMedia::PRIORITY_UNLOADED;
  615. }
  616. else if (!pimpl->getVisible())
  617. {
  618. new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
  619. }
  620. else if (pimpl->hasFocus())
  621. {
  622. new_priority = LLPluginClassMedia::PRIORITY_HIGH;
  623. // Count this against the count of "normal" instances for
  624. // priority purposes
  625. ++impl_count_interest_normal;
  626. }
  627. else if (pimpl->getUsedInUI() || pimpl->getUsedOnHUD() ||
  628. pimpl->isParcelMedia())
  629. {
  630. new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
  631. ++impl_count_interest_normal;
  632. }
  633. else
  634. {
  635. // Look at interest and CPU usage for instances that are not in
  636. // any of the above states.
  637. // Heuristic: if the media texture's approximate screen area is
  638. // less than 1/4 of the native area of the texture, turn it
  639. // down to low instead of normal. This may downsample for
  640. // plugins that support it.
  641. bool media_is_small = false;
  642. F64 approx_interest = pimpl->getApproximateTextureInterest();
  643. if (approx_interest == 0.f)
  644. {
  645. // This media has no current size, which probably means it
  646. // is not loaded.
  647. media_is_small = true;
  648. }
  649. else if (pimpl->getInterest() < approx_interest / 4)
  650. {
  651. media_is_small = true;
  652. }
  653. if (pimpl->getInterest() == 0.f)
  654. {
  655. // This media is completely invisible, due to being outside
  656. // the view frustum or out of range.
  657. new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
  658. }
  659. else if (check_cpu_usage && total_cpu > max_cpu)
  660. {
  661. // Higher priority plugins have already used up the CPU
  662. // budget. Set remaining ones to slideshow priority.
  663. new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW;
  664. }
  665. else if (!media_is_small &&
  666. impl_count_interest_normal < max_normal)
  667. {
  668. // Up to max_normal inworld get normal priority
  669. new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
  670. ++impl_count_interest_normal;
  671. }
  672. else if (impl_count_interest_low + impl_count_interest_normal <
  673. max_low + max_normal)
  674. {
  675. // The next max_low inworld get turned down
  676. new_priority = LLPluginClassMedia::PRIORITY_LOW;
  677. ++impl_count_interest_low;
  678. // Set the low priority size for downsampling to
  679. // approximately the size the texture is displayed at.
  680. {
  681. F32 dimension = sqrtf(pimpl->getInterest());
  682. pimpl->setLowPrioritySizeLimit(ll_roundp(dimension));
  683. }
  684. }
  685. else
  686. {
  687. // Any additional impls (up to max_instances) get very
  688. // infrequent time
  689. new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW;
  690. }
  691. }
  692. if (!pimpl->getUsedInUI() &&
  693. new_priority != LLPluginClassMedia::PRIORITY_UNLOADED)
  694. {
  695. // This is a loadable inworld impl -- the last one in the list
  696. // in this class defines the lowest loadable interest.
  697. lowest_interest_loadable = pimpl;
  698. ++impl_count_total;
  699. }
  700. // Overrides if the window is minimized or we lost focus (taking
  701. // care not to accidentally "raise" the priority either)
  702. if (!gViewerWindowp->getActive() && // viewer window minimized ?
  703. new_priority > LLPluginClassMedia::PRIORITY_HIDDEN)
  704. {
  705. new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
  706. }
  707. else if (!gFocusMgr.getAppHasFocus() && // viewer win lost focus ?
  708. new_priority > LLPluginClassMedia::PRIORITY_LOW)
  709. {
  710. new_priority = LLPluginClassMedia::PRIORITY_LOW;
  711. }
  712. if (!inworld_media_enabled)
  713. {
  714. // If inworld media is locked out, force all inworld media to
  715. // stay unloaded.
  716. if (!pimpl->getUsedInUI())
  717. {
  718. new_priority = LLPluginClassMedia::PRIORITY_UNLOADED;
  719. }
  720. }
  721. // Update the audio stream here as well
  722. if (!inworld_audio_enabled)
  723. {
  724. if (LLViewerParcelMedia::hasParcelAudio() &&
  725. LLViewerParcelMedia::isParcelAudioPlaying())
  726. {
  727. LLViewerParcelMedia::stopStreamingMusic();
  728. }
  729. }
  730. pimpl->setPriority(new_priority);
  731. if (pimpl->getUsedInUI())
  732. {
  733. // Any impl used in the UI should not be in the proximity list.
  734. pimpl->mProximity = -1;
  735. }
  736. else
  737. {
  738. proximity_order.push_back(pimpl);
  739. }
  740. total_cpu += pimpl->getCPUUsage();
  741. if (!pimpl->getUsedInUI())
  742. {
  743. if (pimpl->hasMedia())
  744. {
  745. sAnyMediaShowing = true;
  746. }
  747. if (pimpl != LLViewerParcelMedia::getParcelMedia())
  748. {
  749. if (pimpl->isMediaDisabled())
  750. {
  751. sAnyMediaDisabled = true;
  752. }
  753. else
  754. {
  755. sAnyMediaEnabled = true;
  756. }
  757. }
  758. }
  759. }
  760. }
  761. // Re-calculate this every time.
  762. sLowestLoadableImplInterest = 0.f;
  763. // Only do this calculation if we have hit the impl count limit; up until
  764. // that point we always need to load media data.
  765. if (lowest_interest_loadable && impl_count_total >= (U32)max_instances)
  766. {
  767. // Get the interest value of this impl's object for use by
  768. // isInterestingEnough
  769. LLVOVolume* object = lowest_interest_loadable->getSomeObject();
  770. if (object)
  771. {
  772. // NOTE: Do not use getMediaInterest() here. We want the pixel
  773. // area, not the total media interest, so that we match up with the
  774. // calculation done in LLMediaDataClient.
  775. sLowestLoadableImplInterest = object->getPixelArea();
  776. }
  777. }
  778. {
  779. LL_FAST_TIMER(FTM_MEDIA_SORT2);
  780. // Use a distance-based sort for proximity values.
  781. std::stable_sort(proximity_order.begin(), proximity_order.end(),
  782. proximity_comparator);
  783. }
  784. // Transfer the proximity order to the proximity fields in the objects.
  785. for (S32 i = 0, count = proximity_order.size(); i < count; ++i)
  786. {
  787. proximity_order[i]->mProximity = i;
  788. }
  789. LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu
  790. << LL_ENDL;
  791. }
  792. //static
  793. void LLViewerMedia::setAllMediaEnabled(bool enable, bool parcel_media)
  794. {
  795. // Set "tentative" autoplay first. We need to do this here or else
  796. // re-enabling would not start up the media below.
  797. gSavedSettings.setBool("MediaTentativeAutoPlay", enable);
  798. for (impl_list::iterator iter = sViewerMediaImplList.begin(),
  799. end = sViewerMediaImplList.end();
  800. iter != end; ++iter)
  801. {
  802. LLViewerMediaImpl* pimpl = *iter;
  803. if (!pimpl->getUsedInUI() &&
  804. (parcel_media || pimpl != LLViewerParcelMedia::getParcelMedia()))
  805. {
  806. pimpl->setDisabled(!enable);
  807. }
  808. }
  809. if (!parcel_media)
  810. {
  811. return;
  812. }
  813. // Also do Parcel Media and Parcel Audio
  814. if (enable)
  815. {
  816. LLParcel* parcel = gViewerParcelMgr.getAgentParcel();
  817. if (LLViewerParcelMedia::hasParcelMedia() &&
  818. !LLViewerParcelMedia::isParcelMediaPlaying())
  819. {
  820. LLViewerParcelMedia::playMedia(parcel);
  821. }
  822. if (LLViewerParcelMedia::hasParcelAudio() &&
  823. !LLViewerParcelMedia::isParcelAudioPlaying())
  824. {
  825. LLViewerParcelMedia::playStreamingMusic(parcel);
  826. }
  827. }
  828. else
  829. {
  830. // This actually unloads the impl, as opposed to "stop"ping the media
  831. LLViewerParcelMedia::stop();
  832. LLViewerParcelMedia::stopStreamingMusic();
  833. }
  834. }
  835. //static
  836. void LLViewerMedia::sharedMediaEnable(void*)
  837. {
  838. setAllMediaEnabled(true, false);
  839. }
  840. //static
  841. void LLViewerMedia::sharedMediaDisable(void*)
  842. {
  843. setAllMediaEnabled(false, false);
  844. }
  845. //static
  846. void LLViewerMedia::onAuthSubmit(const LLUUID media_id,
  847. const std::string username,
  848. const std::string password,
  849. bool validated)
  850. {
  851. LLViewerMediaImpl* self =
  852. LLViewerMedia::getMediaImplFromTextureID(media_id);
  853. if (self)
  854. {
  855. LLPluginClassMedia* media = self->getMediaPlugin();
  856. if (media)
  857. {
  858. if (validated)
  859. {
  860. media->sendAuthResponse(true, username, password);
  861. }
  862. else
  863. {
  864. media->sendAuthResponse(false, "", "");
  865. }
  866. }
  867. }
  868. }
  869. //static
  870. void LLViewerMedia::clearAllCookies()
  871. {
  872. // The streaming plugins do not use cookies, so they do not implement
  873. // clear_cookies() and the CEF plugin will only clear its cookies when
  874. // one such plugin is running while this method is called...
  875. // Clear all cookies for all plugins
  876. for (impl_list::iterator iter = sViewerMediaImplList.begin(),
  877. end = sViewerMediaImplList.end();
  878. iter != end; ++iter)
  879. {
  880. LLViewerMediaImpl* pimpl = *iter;
  881. if (pimpl && pimpl->mMediaSource)
  882. {
  883. pimpl->mMediaSource->clear_cookies();
  884. }
  885. }
  886. // Clear the built-in CEF browser cookies (indepedently of the actually
  887. // running plugins, i.e. this works too when no CEF browser plugin is
  888. // running); note that this supposes that the cookies directory name (set
  889. // in media_plugin_cef.cpp) is known: if it changes in the future, this
  890. // code will have to be modified.
  891. // Base directory for the logged-off cache:
  892. std::string cookies_dir = gDirUtil.getOSUserAppDir();
  893. // If logged in, clear the corresponding per-user cache:
  894. std::string linden_user_dir = gDirUtil.getLindenUserDir();
  895. if (!linden_user_dir.empty() && LLStartUp::isLoggedIn())
  896. {
  897. cookies_dir = linden_user_dir;
  898. }
  899. if (cookies_dir.empty())
  900. {
  901. llwarns << "Could not determine the cookies directory location. Aborting."
  902. << llendl;
  903. return;
  904. }
  905. cookies_dir += LL_DIR_DELIM_STR "cef_cache";
  906. if (!LLFile::isdir(cookies_dir))
  907. {
  908. llinfos << "No CEF cache directory found. No cookies." << llendl;
  909. }
  910. else
  911. {
  912. LLDirIterator::deleteFilesInDir(cookies_dir, "Cookies*");
  913. }
  914. }
  915. // Clears the built-in CEF browser cache (there are no caches for streaming
  916. // media plugins, currently). Note that this supposes that the cache directory
  917. // name (set in media_plugin_cef.cpp) and the sub-directories structure (as
  918. // determined by CEF itself) are known: if they change in the future, this code
  919. // will have to be modified.
  920. //static
  921. void LLViewerMedia::clearAllCaches()
  922. {
  923. // Base directory for the logged-off cache:
  924. std::string cache_dir = gDirUtil.getOSUserAppDir();
  925. // If logged in, clear the corresponding per-user cache:
  926. std::string linden_user_dir = gDirUtil.getLindenUserDir();
  927. if (!linden_user_dir.empty() && LLStartUp::isLoggedIn())
  928. {
  929. cache_dir = linden_user_dir;
  930. }
  931. if (cache_dir.empty())
  932. {
  933. llwarns << "Could not determine the cache directory location. Aborting."
  934. << llendl;
  935. return;
  936. }
  937. cache_dir += LL_DIR_DELIM_STR "cef_cache";
  938. if (!LLFile::isdir(cache_dir))
  939. {
  940. llinfos << "No CEF cache directory found." << llendl;
  941. return;
  942. }
  943. // Delete all files in cache *but* the "Cookies*" ones
  944. LLDirIterator::deleteRecursivelyInDir(cache_dir, "Cookies*", true);
  945. }
  946. //static
  947. void LLViewerMedia::setCookiesEnabled(bool enabled)
  948. {
  949. // Set the "cookies enabled" flag for all loaded plugins
  950. for (impl_list::iterator iter = sViewerMediaImplList.begin(),
  951. end = sViewerMediaImplList.end();
  952. iter != end; ++iter)
  953. {
  954. LLViewerMediaImpl* pimpl = *iter;
  955. if (pimpl->mMediaSource)
  956. {
  957. pimpl->mMediaSource->cookies_enabled(enabled);
  958. }
  959. }
  960. }
  961. //static
  962. void LLViewerMedia::setProxyConfig(bool enable, const std::string& host,
  963. S32 port)
  964. {
  965. // Set the proxy config for all loaded plugins
  966. for (impl_list::iterator iter = sViewerMediaImplList.begin(),
  967. end = sViewerMediaImplList.end();
  968. iter != end; ++iter)
  969. {
  970. LLViewerMediaImpl* pimpl = *iter;
  971. if (pimpl->mMediaSource)
  972. {
  973. pimpl->mMediaSource->proxy_setup(enable, host, port);
  974. }
  975. }
  976. }
  977. //static
  978. void LLViewerMedia::setOpenIDCookie(const std::string& url)
  979. {
  980. if (sOpenIDCookie.empty())
  981. {
  982. return;
  983. }
  984. // We want just the hostname to associate it with the cookie
  985. std::string cookie_host;
  986. size_t i = url.find('@');
  987. if (i != std::string::npos)
  988. {
  989. // Hostname starts after the @.
  990. cookie_host = url.substr(i + 1);
  991. }
  992. else
  993. {
  994. // No username/password
  995. i = url.find("://");
  996. if (i != std::string::npos)
  997. {
  998. cookie_host = url.substr(i + 3);
  999. }
  1000. }
  1001. if (!cookie_host.empty())
  1002. {
  1003. i = cookie_host.find(':');
  1004. if (i == std::string::npos)
  1005. {
  1006. // No port number
  1007. i = cookie_host.find('/');
  1008. }
  1009. if (i != std::string::npos)
  1010. {
  1011. cookie_host = cookie_host.substr(0, i);
  1012. }
  1013. }
  1014. // Set the cookie for all open media controls (works only for the CEF
  1015. // plugin).
  1016. if (!url.empty() && !cookie_host.empty())
  1017. {
  1018. LLMediaCtrl::setOpenIdCookie(url, cookie_host, sOpenIDCookie);
  1019. }
  1020. }
  1021. //static
  1022. void LLViewerMedia::openIDSetup(const std::string& url,
  1023. const std::string& token)
  1024. {
  1025. LL_DEBUGS("Media") << "url = \"" << url << "\", token = \""
  1026. << token << "\"" << LL_ENDL;
  1027. if (!gSavedSettings.getBool("MediaGetOpenID"))
  1028. {
  1029. LL_DEBUGS("Media") << "NOT fetching OpenID, as per viewer settings"
  1030. << LL_ENDL;
  1031. return;
  1032. }
  1033. gCoros.launch("LLViewerMedia::openIDSetupCoro",
  1034. boost::bind(&LLViewerMedia::openIDSetupCoro, url, token));
  1035. }
  1036. //static
  1037. void LLViewerMedia::openIDSetupCoro(std::string url, const std::string& token)
  1038. {
  1039. LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions);
  1040. options->setWantHeaders(true);
  1041. LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders);
  1042. headers->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
  1043. headers->append(HTTP_OUT_HEADER_CONTENT_TYPE,
  1044. "application/x-www-form-urlencoded");
  1045. LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
  1046. LLCore::BufferArrayStream bas(rawbody.get());
  1047. bas << std::noskipws << token;
  1048. LLCoreHttpUtil::HttpCoroutineAdapter adapter("openIDSetupCoro");
  1049. LLSD result = adapter.postRawAndSuspend(url, rawbody, options,
  1050. headers);
  1051. LLCore::HttpStatus status =
  1052. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  1053. if (!status)
  1054. {
  1055. llwarns << "Error getting Open ID cookie: " << status.toString()
  1056. << llendl;
  1057. return;
  1058. }
  1059. const LLSD& httpres =
  1060. result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
  1061. const LLSD& header =
  1062. httpres[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
  1063. if (!header.has(HTTP_IN_HEADER_SET_COOKIE))
  1064. {
  1065. llwarns << "No cookie in response." << llendl;
  1066. return;
  1067. }
  1068. // We do not care about the content of the response, only the Set-Cookie
  1069. // header.
  1070. const std::string& cookie = header[HTTP_IN_HEADER_SET_COOKIE].asStringRef();
  1071. // *TODO: What about bad status codes ? Does this destroy previous
  1072. // cookies ?
  1073. LL_DEBUGS("Media") << "Cookie = " << cookie << LL_ENDL;
  1074. openIDCookieResponse(url, cookie);
  1075. }
  1076. //static
  1077. void LLViewerMedia::openIDCookieResponse(const std::string& url,
  1078. const std::string& cookie)
  1079. {
  1080. LL_DEBUGS("Media") << "Cookie received: \"" << cookie << "\"" << LL_ENDL;
  1081. sOpenIDCookie += cookie;
  1082. setOpenIDCookie(url);
  1083. }
  1084. bool LLViewerMedia::hasInWorldMedia()
  1085. {
  1086. // This should be quick, because there should be very few non in-world
  1087. // media impls
  1088. for (impl_list::iterator iter = sViewerMediaImplList.begin(),
  1089. end = sViewerMediaImplList.end();
  1090. iter != end; ++iter)
  1091. {
  1092. LLViewerMediaImpl* pimpl = *iter;
  1093. if (pimpl && !pimpl->getUsedInUI() && !pimpl->isParcelMedia())
  1094. {
  1095. // Found an in-world media impl
  1096. return true;
  1097. }
  1098. }
  1099. return false;
  1100. }
  1101. //static
  1102. void LLViewerMedia::initClass()
  1103. {
  1104. gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL);
  1105. sTeleportFinishConnection =
  1106. gViewerParcelMgr.setTPFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished));
  1107. }
  1108. //static
  1109. void LLViewerMedia::cleanupClass()
  1110. {
  1111. gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL);
  1112. sTeleportFinishConnection.disconnect();
  1113. }
  1114. //static
  1115. void LLViewerMedia::onTeleportFinished()
  1116. {
  1117. // On teleport, clear this setting (i.e. set it to true)
  1118. gSavedSettings.setBool("MediaTentativeAutoPlay", true);
  1119. }
  1120. //static
  1121. void LLViewerMedia::setOnlyAudibleMediaTextureID(const LLUUID& texture_id)
  1122. {
  1123. sOnlyAudibleTextureID = texture_id;
  1124. sForceUpdate = true;
  1125. }
  1126. ///////////////////////////////////////////////////////////////////////////////
  1127. // Media filter implementation:
  1128. ///////////////////////////////////////////////////////////////////////////////
  1129. //static
  1130. bool LLViewerMedia::allowedMedia(std::string media_url)
  1131. {
  1132. LLStringUtil::trim(media_url);
  1133. std::string domain = extractDomain(media_url);
  1134. std::string ip = getDomainIP(domain); // maybe == domain
  1135. if (sAllowedMedia.count(domain) || sAllowedMedia.count(ip))
  1136. {
  1137. return true;
  1138. }
  1139. std::string server;
  1140. for (S32 i = 0, count = sMediaFilterList.size(); i < count; ++i)
  1141. {
  1142. server = sMediaFilterList[i]["domain"].asString();
  1143. if (server == domain || server == ip)
  1144. {
  1145. return (sMediaFilterList[i]["action"].asString() == "allow");
  1146. }
  1147. }
  1148. return false;
  1149. }
  1150. void callback_parcel_media_alert(const LLSD& notification,
  1151. const LLSD& response,
  1152. LLParcel* parcel,
  1153. U32 type,
  1154. std::string domain)
  1155. {
  1156. S32 option = LLNotification::getSelectedOption(notification, response);
  1157. std::string ip = LLViewerMedia::getDomainIP(domain);
  1158. LLSD args;
  1159. if (ip != domain && domain.find('/') == std::string::npos)
  1160. {
  1161. args["DOMAIN"] = domain + " (" + ip + ")";
  1162. }
  1163. else
  1164. {
  1165. args["DOMAIN"] = domain;
  1166. }
  1167. if (option == 0 || option == 3) // Allow or Whitelist
  1168. {
  1169. LLViewerMedia::sAllowedMedia.emplace(domain);
  1170. if (option == 3) // Whitelist
  1171. {
  1172. LLSD newmedia;
  1173. newmedia["domain"] = domain;
  1174. newmedia["action"] = "allow";
  1175. LLViewerMedia::sMediaFilterList.append(newmedia);
  1176. if (ip != domain && domain.find('/') == std::string::npos)
  1177. {
  1178. newmedia["domain"] = ip;
  1179. LLViewerMedia::sMediaFilterList.append(newmedia);
  1180. }
  1181. LLViewerMedia::saveDomainFilterList();
  1182. args["LISTED"] = "whitelisted";
  1183. gNotifications.add("MediaListed", args);
  1184. }
  1185. if (parcel == gViewerParcelMgr.getAgentParcel())
  1186. {
  1187. if (type == 0)
  1188. {
  1189. LLViewerParcelMedia::playMedia(parcel, false);
  1190. }
  1191. else
  1192. {
  1193. LLViewerParcelMedia::playStreamingMusic(parcel, false);
  1194. }
  1195. }
  1196. }
  1197. else if (option == 1 || option == 2) // Deny or Blacklist
  1198. {
  1199. LLViewerMedia::sDeniedMedia.emplace(domain);
  1200. if (ip != domain && domain.find('/') == std::string::npos)
  1201. {
  1202. LLViewerMedia::sDeniedMedia.emplace(ip);
  1203. }
  1204. if (type == 1 && parcel == gViewerParcelMgr.getAgentParcel())
  1205. {
  1206. LLViewerParcelMedia::stopStreamingMusic();
  1207. }
  1208. if (option == 1) // Deny
  1209. {
  1210. gNotifications.add("MediaBlocked", args);
  1211. }
  1212. else // Blacklist
  1213. {
  1214. LLSD newmedia;
  1215. newmedia["domain"] = domain;
  1216. newmedia["action"] = "deny";
  1217. LLViewerMedia::sMediaFilterList.append(newmedia);
  1218. if (ip != domain && domain.find('/') == std::string::npos)
  1219. {
  1220. newmedia["domain"] = ip;
  1221. LLViewerMedia::sMediaFilterList.append(newmedia);
  1222. }
  1223. LLViewerMedia::saveDomainFilterList();
  1224. args["LISTED"] = "blacklisted";
  1225. gNotifications.add("MediaListed", args);
  1226. }
  1227. }
  1228. LLViewerMedia::sMediaQueries.erase(domain);
  1229. SLFloaterMediaFilter::setDirty();
  1230. }
  1231. //static
  1232. void LLViewerMedia::filterParcelMedia(LLParcel* parcel, U32 type)
  1233. {
  1234. if (parcel != gViewerParcelMgr.getAgentParcel())
  1235. {
  1236. // The parcel just changed (may occur right out after a TP)
  1237. sIsUserAction = false;
  1238. return;
  1239. }
  1240. std::string media_url;
  1241. if (type == 0)
  1242. {
  1243. media_url = parcel->getMediaURL();
  1244. }
  1245. else
  1246. {
  1247. media_url = parcel->getMusicURL();
  1248. }
  1249. LLStringUtil::trim(media_url);
  1250. std::string domain = extractDomain(media_url);
  1251. if (sMediaQueries.count(domain) > 0)
  1252. {
  1253. sIsUserAction = false;
  1254. return;
  1255. }
  1256. std::string ip = getDomainIP(domain);
  1257. if (sIsUserAction)
  1258. {
  1259. // This was a user manual request to play this media, so give it
  1260. // another chance...
  1261. sIsUserAction = false;
  1262. bool dirty = false;
  1263. if (sDeniedMedia.count(domain))
  1264. {
  1265. sDeniedMedia.erase(domain);
  1266. dirty = true;
  1267. }
  1268. if (sDeniedMedia.count(ip))
  1269. {
  1270. sDeniedMedia.erase(ip);
  1271. dirty = true;
  1272. }
  1273. if (dirty)
  1274. {
  1275. SLFloaterMediaFilter::setDirty();
  1276. }
  1277. }
  1278. std::string media_action;
  1279. if (media_url.empty())
  1280. {
  1281. media_action = "allow";
  1282. }
  1283. else if (!sMediaFilterListLoaded || sDeniedMedia.count(domain) ||
  1284. sDeniedMedia.count(ip))
  1285. {
  1286. media_action = "ignore";
  1287. }
  1288. else if (sAllowedMedia.count(domain) || sAllowedMedia.count(ip))
  1289. {
  1290. media_action = "allow";
  1291. }
  1292. else
  1293. {
  1294. std::string server;
  1295. for (S32 i = 0, count = sMediaFilterList.size(); i < count; ++i)
  1296. {
  1297. server = sMediaFilterList[i]["domain"].asString();
  1298. if (server == domain || server == ip)
  1299. {
  1300. media_action = sMediaFilterList[i]["action"].asString();
  1301. break;
  1302. }
  1303. }
  1304. }
  1305. if (media_action == "allow")
  1306. {
  1307. if (type == 0)
  1308. {
  1309. LLViewerParcelMedia::playMedia(parcel, false);
  1310. }
  1311. else
  1312. {
  1313. LLViewerParcelMedia::playStreamingMusic(parcel, false);
  1314. }
  1315. return;
  1316. }
  1317. if (media_action == "ignore")
  1318. {
  1319. if (type == 1)
  1320. {
  1321. LLViewerParcelMedia::stopStreamingMusic();
  1322. }
  1323. return;
  1324. }
  1325. LLSD args;
  1326. if (ip != domain && domain.find('/') == std::string::npos)
  1327. {
  1328. args["DOMAIN"] = domain + " (" + ip + ")";
  1329. }
  1330. else
  1331. {
  1332. args["DOMAIN"] = domain;
  1333. }
  1334. if (media_action == "deny")
  1335. {
  1336. gNotifications.add("MediaBlocked", args);
  1337. if (type == 1)
  1338. {
  1339. LLViewerParcelMedia::stopStreamingMusic();
  1340. }
  1341. // So to avoid other "blocked" messages later in the session
  1342. // for this url should it be requested again by a script.
  1343. // We do not add the IP, on purpose (want to show different
  1344. // blocks for different domains pointing to the same IP).
  1345. sDeniedMedia.emplace(domain);
  1346. }
  1347. else
  1348. {
  1349. sMediaQueries.emplace(domain);
  1350. args["URL"] = media_url;
  1351. if (type == 0)
  1352. {
  1353. args["TYPE"] = "media";
  1354. }
  1355. else
  1356. {
  1357. args["TYPE"] = "audio";
  1358. }
  1359. gNotifications.add("ParcelMediaAlert", args, LLSD(),
  1360. boost::bind(callback_parcel_media_alert, _1, _2,
  1361. parcel, type, domain));
  1362. }
  1363. }
  1364. void callback_media_alert(const LLSD& notification, const LLSD& response,
  1365. LLViewerMediaImpl* impl, std::string domain)
  1366. {
  1367. S32 option = LLNotification::getSelectedOption(notification, response);
  1368. std::string ip = LLViewerMedia::getDomainIP(domain);
  1369. LLSD args;
  1370. if (ip != domain && domain.find('/') == std::string::npos)
  1371. {
  1372. args["DOMAIN"] = domain + " (" + ip + ")";
  1373. }
  1374. else
  1375. {
  1376. args["DOMAIN"] = domain;
  1377. }
  1378. if (option == 0 || option == 3) // Allow or Whitelist
  1379. {
  1380. LLViewerMedia::sAllowedMedia.emplace(domain);
  1381. if (option == 3) // Whitelist
  1382. {
  1383. LLSD newmedia;
  1384. newmedia["domain"] = domain;
  1385. newmedia["action"] = "allow";
  1386. LLViewerMedia::sMediaFilterList.append(newmedia);
  1387. if (ip != domain && domain.find('/') == std::string::npos)
  1388. {
  1389. newmedia["domain"] = ip;
  1390. LLViewerMedia::sMediaFilterList.append(newmedia);
  1391. }
  1392. LLViewerMedia::saveDomainFilterList();
  1393. args["LISTED"] = "whitelisted";
  1394. gNotifications.add("MediaListed", args);
  1395. }
  1396. if (is_media_impl_valid(impl))
  1397. {
  1398. impl->navigateInternal();
  1399. }
  1400. }
  1401. else if (option == 1 || option == 2) // Deny or Blacklist
  1402. {
  1403. LLViewerMedia::sDeniedMedia.emplace(domain);
  1404. if (ip != domain && domain.find('/') == std::string::npos)
  1405. {
  1406. LLViewerMedia::sDeniedMedia.emplace(ip);
  1407. }
  1408. if (option == 1) // Deny
  1409. {
  1410. gNotifications.add("MediaBlocked", args);
  1411. }
  1412. else // Blacklist
  1413. {
  1414. LLSD newmedia;
  1415. newmedia["domain"] = domain;
  1416. newmedia["action"] = "deny";
  1417. LLViewerMedia::sMediaFilterList.append(newmedia);
  1418. if (ip != domain && domain.find('/') == std::string::npos)
  1419. {
  1420. newmedia["domain"] = ip;
  1421. LLViewerMedia::sMediaFilterList.append(newmedia);
  1422. }
  1423. LLViewerMedia::saveDomainFilterList();
  1424. args["LISTED"] = "blacklisted";
  1425. gNotifications.add("MediaListed", args);
  1426. }
  1427. if (is_media_impl_valid(impl))
  1428. {
  1429. impl->setDisabled(true);
  1430. }
  1431. }
  1432. LLViewerMedia::sMediaQueries.erase(domain);
  1433. SLFloaterMediaFilter::setDirty();
  1434. }
  1435. //static
  1436. bool LLViewerMedia::filterMedia(LLViewerMediaImpl* impl)
  1437. {
  1438. if (!is_media_impl_valid(impl))
  1439. {
  1440. return true;
  1441. }
  1442. std::string media_url = impl->getMediaURL();
  1443. LLStringUtil::trim(media_url);
  1444. if (media_url.find("://") == std::string::npos)
  1445. {
  1446. // That's a filename...
  1447. return false;
  1448. }
  1449. LLURI uri(media_url);
  1450. std::string scheme = uri.scheme();
  1451. if (scheme == "data" || scheme == "file" || scheme == "about")
  1452. {
  1453. return false;
  1454. }
  1455. std::string domain = extractDomain(media_url);
  1456. if (sMediaQueries.count(domain) > 0 || !sMediaFilterListLoaded)
  1457. {
  1458. // Pending actions in progress, deny for now.
  1459. return true;
  1460. }
  1461. std::string ip = getDomainIP(domain);
  1462. std::string media_action;
  1463. if (media_url.empty())
  1464. {
  1465. media_action = "allow";
  1466. }
  1467. else if (sDeniedMedia.count(domain) || sDeniedMedia.count(ip))
  1468. {
  1469. media_action = "ignore";
  1470. }
  1471. else if (sAllowedMedia.count(domain) || sAllowedMedia.count(ip))
  1472. {
  1473. media_action = "allow";
  1474. }
  1475. else
  1476. {
  1477. std::string server;
  1478. for (S32 i = 0, count = sMediaFilterList.size(); i < count; ++i)
  1479. {
  1480. server = sMediaFilterList[i]["domain"].asString();
  1481. if (server == domain || server == ip)
  1482. {
  1483. media_action = sMediaFilterList[i]["action"].asString();
  1484. break;
  1485. }
  1486. }
  1487. }
  1488. if (media_action == "allow")
  1489. {
  1490. return false;
  1491. }
  1492. if (media_action == "ignore")
  1493. {
  1494. impl->setDisabled(true);
  1495. return true;
  1496. }
  1497. LLSD args;
  1498. if (ip != domain && domain.find('/') == std::string::npos)
  1499. {
  1500. args["DOMAIN"] = domain + " (" + ip + ")";
  1501. }
  1502. else
  1503. {
  1504. args["DOMAIN"] = domain;
  1505. }
  1506. if (media_action == "deny")
  1507. {
  1508. gNotifications.add("MediaBlocked", args);
  1509. // So to avoid other "blocked" messages later in the session
  1510. // for this url should it be requested again by a script.
  1511. // We do not add the IP, on purpose (want to show different
  1512. // blocks for different domains pointing to the same IP).
  1513. sDeniedMedia.emplace(domain);
  1514. impl->setDisabled(true);
  1515. return true;
  1516. }
  1517. else
  1518. {
  1519. sMediaQueries.emplace(domain);
  1520. args["URL"] = media_url;
  1521. gNotifications.add("MediaAlert", args, LLSD(),
  1522. boost::bind(callback_media_alert, _1, _2, impl,
  1523. domain));
  1524. return true;
  1525. }
  1526. }
  1527. //static
  1528. void LLViewerMedia::saveDomainFilterList()
  1529. {
  1530. std::string filename = gDirUtil.getFullPath(LL_PATH_PER_ACCOUNT,
  1531. "media_filter.xml");
  1532. llofstream filestream(filename.c_str());
  1533. if (filestream.is_open())
  1534. {
  1535. LLSDSerialize::toPrettyXML(sMediaFilterList, filestream);
  1536. filestream.close();
  1537. }
  1538. else
  1539. {
  1540. llwarns << "Could not open file '" << filename << "' for writing."
  1541. << llendl;
  1542. }
  1543. }
  1544. //static
  1545. bool LLViewerMedia::loadDomainFilterList()
  1546. {
  1547. sMediaFilterListLoaded = true;
  1548. std::string filename = gDirUtil.getFullPath(LL_PATH_PER_ACCOUNT,
  1549. "media_filter.xml");
  1550. if (!LLFile::isfile(filename))
  1551. {
  1552. LLSD emptyllsd;
  1553. llofstream filestream(filename.c_str());
  1554. if (filestream.is_open())
  1555. {
  1556. LLSDSerialize::toPrettyXML(emptyllsd, filestream);
  1557. filestream.close();
  1558. }
  1559. else
  1560. {
  1561. llwarns << "Could not open file '" << filename << "' for writing."
  1562. << llendl;
  1563. }
  1564. }
  1565. if (LLFile::isfile(filename))
  1566. {
  1567. llifstream filestream(filename.c_str());
  1568. if (filestream.is_open())
  1569. {
  1570. LLSDSerialize::fromXML(sMediaFilterList, filestream);
  1571. filestream.close();
  1572. }
  1573. SLFloaterMediaFilter::setDirty();
  1574. return true;
  1575. }
  1576. else
  1577. {
  1578. return false;
  1579. }
  1580. }
  1581. //static
  1582. void LLViewerMedia::clearDomainFilterList()
  1583. {
  1584. sMediaFilterList.clear();
  1585. sAllowedMedia.clear();
  1586. sDeniedMedia.clear();
  1587. saveDomainFilterList();
  1588. gNotifications.add("MediaFiltersCleared");
  1589. SLFloaterMediaFilter::setDirty();
  1590. }
  1591. //static
  1592. std::string LLViewerMedia::extractDomain(std::string url)
  1593. {
  1594. static std::string last_region = "@";
  1595. if (url.empty())
  1596. {
  1597. return url;
  1598. }
  1599. LLStringUtil::toLower(url);
  1600. size_t pos = url.find("//");
  1601. if (pos != std::string::npos)
  1602. {
  1603. size_t count = url.size() - pos + 2;
  1604. url = url.substr(pos + 2, count);
  1605. }
  1606. // Check that there is at least one slash in the URL and add a trailing
  1607. // one if not (for media/audio URLs such as http://mydomain.net)
  1608. if (url.find('/') == std::string::npos)
  1609. {
  1610. url += '/';
  1611. }
  1612. // If there's a user:password@ part, remove it
  1613. pos = url.find('@');
  1614. if (pos != std::string::npos && pos < url.find('/'))
  1615. {
  1616. // if '@' is not before the first '/', then it's not a user:password
  1617. size_t count = url.size() - pos + 1;
  1618. url = url.substr(pos + 1, count);
  1619. }
  1620. const LLHost& host = gAgent.getRegionHost();
  1621. if (host.isOk() &&
  1622. (url.find(host.getHostName()) == 0 || url.find(last_region) == 0))
  1623. {
  1624. // This must be a scripted object rezzed in the region:
  1625. // extend the concept of "domain" to encompass the scripted object
  1626. // server Id and avoid blocking all other objects at once in this
  1627. // region...
  1628. // Get rid of any port number
  1629. pos = url.find('/'); // We earlier made sure that there is one
  1630. url = host.getHostName() + url.substr(pos);
  1631. pos = url.find('?');
  1632. if (pos != std::string::npos)
  1633. {
  1634. // Get rid of any parameter
  1635. url = url.substr(0, pos);
  1636. }
  1637. pos = url.rfind('/');
  1638. if (pos != std::string::npos)
  1639. {
  1640. // Get rid of the filename, if any, keeping only the server + path
  1641. url = url.substr(0, pos);
  1642. }
  1643. }
  1644. else
  1645. {
  1646. pos = url.find(':');
  1647. if (pos != std::string::npos && pos < url.find('/'))
  1648. {
  1649. // Keep anything before the port number and strip the rest off
  1650. url = url.substr(0, pos);
  1651. }
  1652. else
  1653. {
  1654. pos = url.find('/'); // We earlier made sure that there's one
  1655. url = url.substr(0, pos);
  1656. }
  1657. }
  1658. // Remember this region, so to cope with requests occuring just after a
  1659. // TP out of it.
  1660. if (host.isOk())
  1661. {
  1662. last_region = host.getHostName();
  1663. }
  1664. return url;
  1665. }
  1666. //static
  1667. std::string LLViewerMedia::getDomainIP(const std::string& domain, bool force)
  1668. {
  1669. std::string ip = domain; // Default for no lookups or IP domains
  1670. static const std::regex ipv4("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
  1671. // Check to see if the domain is already an IP
  1672. try
  1673. {
  1674. if (std::regex_match(domain, ipv4))
  1675. {
  1676. return ip;
  1677. }
  1678. }
  1679. catch (std::regex_error& e)
  1680. {
  1681. llwarns << "Regex error: " << e.what() << llendl;
  1682. }
  1683. // The domain is a name, not an IP. Make a DNS lookup.
  1684. std::map<std::string, std::string>::iterator it = sDNSlookups.find(domain);
  1685. if (it != sDNSlookups.end())
  1686. {
  1687. ip = it->second;
  1688. }
  1689. else if (force || gSavedSettings.getBool("MediaLookupIP"))
  1690. {
  1691. // Lookup the domain to get its IP.
  1692. // This incurs a short pause (one second or so) on succesful lookups
  1693. // and a long pause (several seconds) on failing lookups (bad domain).
  1694. LLHost host;
  1695. host.setHostByName(domain);
  1696. ip = host.getIPString();
  1697. // Cache this (domain, ip) pair for later lookups
  1698. sDNSlookups.emplace(domain, ip);
  1699. }
  1700. return ip;
  1701. }
  1702. ///////////////////////////////////////////////////////////////////////////////
  1703. // LLViewerMediaImpl
  1704. ///////////////////////////////////////////////////////////////////////////////
  1705. LLViewerMediaImpl::LLViewerMediaImpl(const LLUUID& texture_id,
  1706. S32 media_width,
  1707. S32 media_height,
  1708. bool media_auto_scale,
  1709. bool media_loop)
  1710. : mMediaSource(NULL),
  1711. mMovieImageHasMips(false),
  1712. mMediaWidth(media_width),
  1713. mMediaHeight(media_height),
  1714. mMediaAutoScale(media_auto_scale),
  1715. mMediaLoop(media_loop),
  1716. mNeedsNewTexture(true),
  1717. mTextureUsedWidth(0),
  1718. mTextureUsedHeight(0),
  1719. mSuspendUpdates(false),
  1720. mTextureUpdatePending(false),
  1721. mVisible(true),
  1722. mLastSetCursor(UI_CURSOR_ARROW),
  1723. mMediaNavState(MEDIANAVSTATE_NONE),
  1724. mInterest(0.f),
  1725. mUsedInUI(false),
  1726. mUsedOnHUD(false),
  1727. mHasFocus(false),
  1728. mPriority(LLPluginClassMedia::PRIORITY_UNLOADED),
  1729. mNavigateRediscoverType(false),
  1730. mNavigateServerRequest(false),
  1731. mMediaSourceFailed(false),
  1732. mRequestedVolume(1.f),
  1733. mPreviousVolume(1.f),
  1734. mIsMuted(false),
  1735. mNeedsMuteCheck(false),
  1736. mPreviousMediaState(MEDIA_NONE),
  1737. mPreviousMediaTime(0.f),
  1738. mIsDisabled(false),
  1739. mIsParcelMedia(false),
  1740. mProximity(-1),
  1741. mProximityDistance(0.f),
  1742. mMediaAutoPlay(false),
  1743. mInNearbyMediaList(false),
  1744. mBackgroundColor(LLColor4::black), // Do not set to white or may get "white flash" bug.
  1745. mNavigateSuspended(false),
  1746. mNavigateSuspendedDeferred(false),
  1747. mIsUpdated(false),
  1748. mTrustedBrowser(false),
  1749. mZoomFactor(1.0),
  1750. mFilterURL(true),
  1751. mMimeProbe()
  1752. {
  1753. // Set up the mute list observer if it has not been set up already.
  1754. if (!sViewerMediaMuteListObserverInitialized)
  1755. {
  1756. LLMuteList::addObserver(&sViewerMediaMuteListObserver);
  1757. sViewerMediaMuteListObserverInitialized = true;
  1758. }
  1759. add_media_impl(this);
  1760. setTextureID(texture_id);
  1761. // Connect this impl to the media texture, creating it if it does not
  1762. // exist. This is necessary because we need to be able to use
  1763. // getMaxVirtualSize() even if the media plugin is not loaded.
  1764. LLViewerMediaTexture* media_tex =
  1765. LLViewerTextureManager::getMediaTexture(mTextureId);
  1766. if (media_tex)
  1767. {
  1768. media_tex->setMediaImpl();
  1769. }
  1770. }
  1771. LLViewerMediaImpl::~LLViewerMediaImpl()
  1772. {
  1773. destroyMediaSource();
  1774. LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId);
  1775. setTextureID();
  1776. remove_media_impl(this);
  1777. }
  1778. void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin,
  1779. LLViewerMediaObserver::EMediaEvent event)
  1780. {
  1781. // Broadcast to observers using the superclass version
  1782. LLViewerMediaEventEmitter::emitEvent(plugin, event);
  1783. // If this media is on one or more LLVOVolume objects, tell them about the
  1784. // event as well.
  1785. for (std::list<LLVOVolume*>::iterator iter = mObjectList.begin(),
  1786. end = mObjectList.end();
  1787. iter != end; )
  1788. {
  1789. LLVOVolume* self = *iter++;
  1790. self->mediaEvent(this, plugin, event);
  1791. }
  1792. }
  1793. bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type)
  1794. {
  1795. bool mimeTypeChanged = (mMimeType != mime_type);
  1796. bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) !=
  1797. LLMIMETypes::implType(mime_type));
  1798. if (!mMediaSource || pluginChanged)
  1799. {
  1800. if (!initializePlugin(mime_type))
  1801. {
  1802. llwarns << "plugin intialization failed for mime type: "
  1803. << mime_type << llendl;
  1804. return false;
  1805. }
  1806. }
  1807. else if (mimeTypeChanged)
  1808. {
  1809. // The same plugin should be able to handle the new media,
  1810. // just update the stored mime type.
  1811. mMimeType = mime_type;
  1812. }
  1813. return mMediaSource != NULL;
  1814. }
  1815. void LLViewerMediaImpl::createMediaSource()
  1816. {
  1817. if (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
  1818. {
  1819. // This media should not be created yet.
  1820. return;
  1821. }
  1822. if (!mMediaURL.empty())
  1823. {
  1824. navigateInternal();
  1825. }
  1826. else if (!mMimeType.empty())
  1827. {
  1828. if (!initializeMedia(mMimeType))
  1829. {
  1830. llwarns << "Failed to initialize media for mime type " << mMimeType
  1831. << llendl;
  1832. }
  1833. }
  1834. }
  1835. void LLViewerMediaImpl::destroyMediaSource()
  1836. {
  1837. mNeedsNewTexture = true;
  1838. if (mTextureId.notNull())
  1839. {
  1840. // Tell the viewer media texture it's no longer active
  1841. LLViewerMediaTexture* tex = LLViewerTextureManager::findMediaTexture(mTextureId);
  1842. if (tex)
  1843. {
  1844. tex->setPlaying(false);
  1845. }
  1846. }
  1847. cancelMimeTypeProbe();
  1848. mLock.lock(); // Delay tear-down while bg thread is updating
  1849. if (mMediaSource)
  1850. {
  1851. mMediaSource->setDeleteOK(true);
  1852. delete mMediaSource;
  1853. mMediaSource = NULL;
  1854. }
  1855. mLock.unlock();
  1856. }
  1857. void LLViewerMediaImpl::setMediaType(const std::string& media_type)
  1858. {
  1859. mMimeType = media_type;
  1860. }
  1861. //static
  1862. LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type,
  1863. // NOTE: owner may be NULL
  1864. LLPluginClassMediaOwner* owner,
  1865. S32 default_width,
  1866. S32 default_height,
  1867. const std::string target)
  1868. {
  1869. std::string plugin_basename = LLMIMETypes::implType(media_type);
  1870. if (plugin_basename.empty())
  1871. {
  1872. llwarns << "Could not find plugin for media type " << media_type
  1873. << llendl;
  1874. }
  1875. else
  1876. {
  1877. std::string launcher_name = gDirUtil.getLLPluginLauncher();
  1878. if (plugin_basename == "media_plugin_gstreamer10" ||
  1879. plugin_basename == "media_plugin_libvlc" ||
  1880. plugin_basename == "streaming_plugin")
  1881. {
  1882. plugin_basename = "media_plugin_gstreamer";
  1883. }
  1884. std::string plugin_name =
  1885. gDirUtil.getLLPluginFilename(plugin_basename);
  1886. std::string user_data_path = gDirUtil.getOSUserAppDir();
  1887. // Fix for EXT-5960 - make browser profile specific to user (cache,
  1888. // cookies etc). If the linden username returned is blank, that can
  1889. // only mean we are at the login page displaying login Web page or Web
  1890. // browser test via Develop menu. In this case we just use whatever
  1891. // gDirUtil.getOSUserAppDir() gives us (this is what we always used
  1892. // before this change)
  1893. std::string linden_user_dir = gDirUtil.getLindenUserDir();
  1894. if (!linden_user_dir.empty() && LLStartUp::isLoggedIn())
  1895. {
  1896. // gDirUtil.getLindenUserDir() is whole path, not just Linden name
  1897. user_data_path = linden_user_dir;
  1898. }
  1899. user_data_path += LL_DIR_DELIM_STR;
  1900. // See if the plugin executable exists
  1901. if (!LLFile::isfile(launcher_name))
  1902. {
  1903. llwarns_once << "Could not find launcher at " << launcher_name
  1904. << llendl;
  1905. }
  1906. else if (!LLFile::isfile(plugin_name))
  1907. {
  1908. llwarns_once << "Could not find plugin at " << plugin_name
  1909. << llendl;
  1910. }
  1911. else
  1912. {
  1913. LLPluginClassMedia* pluginp = new LLPluginClassMedia(owner);
  1914. pluginp->setSize(default_width, default_height);
  1915. pluginp->setUserDataPath(user_data_path);
  1916. pluginp->setLanguageCode(LLUI::getLanguage());
  1917. if (plugin_basename == "media_plugin_cef")
  1918. {
  1919. pluginp->cookies_enabled(gSavedSettings.getBool("CookiesEnabled"));
  1920. pluginp->setJavascriptEnabled(gSavedSettings.getBool("BrowserJavascriptEnabled"));
  1921. #if CHROME_VERSION_MAJOR < 100
  1922. pluginp->setPluginsEnabled(gSavedSettings.getBool("BrowserPluginsEnabled"));
  1923. #endif
  1924. pluginp->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent());
  1925. #ifdef HB_DULLAHAN_EXTENDED
  1926. pluginp->setPreferredFont(gSavedSettings.getString("CEFPreferredFont"));
  1927. pluginp->setMinimumFontSize(gSavedSettings.getU32("CEFMinimumFontSize"));
  1928. pluginp->setDefaultFontSize(gSavedSettings.getU32("CEFDefaultFontSize"));
  1929. pluginp->setRemoteFontsEnabled(gSavedSettings.getBool("CEFRemoteFonts"));
  1930. #endif
  1931. }
  1932. pluginp->enableMediaPluginDebugging(gSavedSettings.getBool("MediaPluginDebugging"));
  1933. pluginp->setTarget(target);
  1934. const std::string& plugin_dir = gDirUtil.getLLPluginDir();
  1935. if (pluginp->init(launcher_name, plugin_dir, plugin_name, false))
  1936. {
  1937. return pluginp;
  1938. }
  1939. else
  1940. {
  1941. llwarns << "Failed to initialize plugin. Destroying media."
  1942. << llendl;
  1943. delete pluginp;
  1944. }
  1945. }
  1946. }
  1947. static std::set<std::string> warned_missing_types;
  1948. if (!warned_missing_types.count(media_type)) // Warn only once per session
  1949. {
  1950. warned_missing_types.emplace(media_type);
  1951. llwarns << "Plugin intialization failed for mime type: " << media_type
  1952. << llendl;
  1953. LLSD args;
  1954. args["MIME_TYPE"] = media_type;
  1955. gNotifications.add("NoPlugin", args);
  1956. }
  1957. return NULL;
  1958. }
  1959. bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
  1960. {
  1961. if (mMediaSource)
  1962. {
  1963. // Save the previous media source's last set size before destroying it.
  1964. mMediaWidth = mMediaSource->getSetWidth();
  1965. mMediaHeight = mMediaSource->getSetHeight();
  1966. }
  1967. // Always delete the old media impl first.
  1968. destroyMediaSource();
  1969. // and unconditionally set the mime type
  1970. mMimeType = media_type;
  1971. if (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
  1972. {
  1973. // This impl should not be loaded at this time.
  1974. LL_DEBUGS("PluginPriority") << this
  1975. << "Not loading (PRIORITY_UNLOADED)"
  1976. << LL_ENDL;
  1977. return false;
  1978. }
  1979. // If we got here, we want to ignore previous init failures.
  1980. mMediaSourceFailed = false;
  1981. // Save the MIME type that really caused the plugin to load
  1982. mCurrentMimeType = mMimeType;
  1983. LLPluginClassMedia* pluginp = newSourceFromMediaType(media_type, this,
  1984. mMediaWidth,
  1985. mMediaHeight,
  1986. mTarget);
  1987. if (pluginp)
  1988. {
  1989. pluginp->injectOpenIdCookie();
  1990. pluginp->setDisableTimeout(gSavedSettings.getBool("DebugPluginDisableTimeout"));
  1991. pluginp->setLoop(mMediaLoop);
  1992. pluginp->setAutoScale(mMediaAutoScale);
  1993. pluginp->focus(mHasFocus);
  1994. pluginp->setBackgroundColor(mBackgroundColor);
  1995. pluginp->proxy_setup(gSavedSettings.getBool("BrowserProxyEnabled"),
  1996. gSavedSettings.getString("BrowserProxyAddress"),
  1997. gSavedSettings.getS32("BrowserProxyPort"));
  1998. if (gSavedSettings.getBool("BrowserIgnoreSSLCertErrors"))
  1999. {
  2000. pluginp->ignore_ssl_cert_errors(true);
  2001. }
  2002. // The correct way to deal with certificates it to load ours from
  2003. // ca-bundle.crt and append them to the ones the browser plugin loads
  2004. // from your system location.
  2005. pluginp->addCertificateFilePath(gDirUtil.getCRTFile());
  2006. mMediaSource = pluginp;
  2007. mMediaSource->setDeleteOK(false);
  2008. updateVolume();
  2009. return true;
  2010. }
  2011. // Make sure the timer does not try re-initing this plugin repeatedly until
  2012. // something else changes.
  2013. mMediaSourceFailed = true;
  2014. return false;
  2015. }
  2016. void LLViewerMediaImpl::loadURI()
  2017. {
  2018. if (mMediaSource && !mMediaURL.empty())
  2019. {
  2020. // Trim whitespace from front and back of URL - fixes EXT-5363
  2021. LLStringUtil::trim(mMediaURL);
  2022. if (mMediaURL.empty()) return;
  2023. std::string uri = LLURI::escapePathAndData(mMediaURL);
  2024. // Do not log the query parts
  2025. std::string sanitized_uri;
  2026. LLURI u(uri);
  2027. if (u.query().empty())
  2028. {
  2029. sanitized_uri = uri;
  2030. }
  2031. else
  2032. {
  2033. sanitized_uri = u.scheme() + "://" + u.authority() + u.path();
  2034. }
  2035. llinfos << "Asking media source to load URI: " << sanitized_uri
  2036. << llendl;
  2037. mMediaSource->loadURI(uri);
  2038. // A non-zero mPreviousMediaTime means that either this media was
  2039. // previously unloaded by the priority code while playing/paused, or a
  2040. // seek happened before the media loaded. In either case, seek to the
  2041. // saved time.
  2042. if (mPreviousMediaTime != 0.f)
  2043. {
  2044. seek(mPreviousMediaTime);
  2045. }
  2046. if (mPreviousMediaState == MEDIA_PLAYING)
  2047. {
  2048. // This media was playing before this instance was unloaded.
  2049. start();
  2050. }
  2051. else if (mPreviousMediaState == MEDIA_PAUSED)
  2052. {
  2053. // This media was paused before this instance was unloaded.
  2054. pause();
  2055. }
  2056. else
  2057. {
  2058. // No relevant previous media play state; if we are loading the
  2059. // URL, we want to start playing.
  2060. start();
  2061. }
  2062. }
  2063. }
  2064. void LLViewerMediaImpl::setSize(int width, int height)
  2065. {
  2066. mMediaWidth = width;
  2067. mMediaHeight = height;
  2068. if (mMediaSource)
  2069. {
  2070. mMediaSource->setSize(width, height);
  2071. }
  2072. }
  2073. void LLViewerMediaImpl::play()
  2074. {
  2075. // If the media source is not there, try to initialize it and load an URL.
  2076. if (mMediaSource == NULL)
  2077. {
  2078. if (!initializePlugin(mMimeType))
  2079. {
  2080. // Plugin failed initialization... should assert or something
  2081. return;
  2082. }
  2083. // Only do this if the media source was just loaded.
  2084. loadURI();
  2085. }
  2086. // always start the media
  2087. start();
  2088. }
  2089. void LLViewerMediaImpl::stop()
  2090. {
  2091. if (mMediaSource)
  2092. {
  2093. mMediaSource->stop();
  2094. //destroyMediaSource();
  2095. }
  2096. }
  2097. void LLViewerMediaImpl::pause()
  2098. {
  2099. if (mMediaSource)
  2100. {
  2101. mMediaSource->pause();
  2102. }
  2103. else
  2104. {
  2105. mPreviousMediaState = MEDIA_PAUSED;
  2106. }
  2107. }
  2108. void LLViewerMediaImpl::start()
  2109. {
  2110. if (mMediaSource)
  2111. {
  2112. mMediaSource->start();
  2113. }
  2114. else
  2115. {
  2116. mPreviousMediaState = MEDIA_PLAYING;
  2117. }
  2118. }
  2119. void LLViewerMediaImpl::seek(F32 time)
  2120. {
  2121. if (mMediaSource)
  2122. {
  2123. mMediaSource->seek(time);
  2124. }
  2125. else
  2126. {
  2127. // Save the seek time to be set when the media is loaded.
  2128. mPreviousMediaTime = time;
  2129. }
  2130. }
  2131. void LLViewerMediaImpl::skipBack(F32 step_scale)
  2132. {
  2133. if (mMediaSource && mMediaSource->pluginSupportsMediaTime())
  2134. {
  2135. F64 back_step = mMediaSource->getCurrentTime() -
  2136. step_scale * mMediaSource->getDuration();
  2137. if (back_step < 0.0)
  2138. {
  2139. back_step = 0.0;
  2140. }
  2141. mMediaSource->seek(back_step);
  2142. }
  2143. }
  2144. void LLViewerMediaImpl::skipForward(F32 step_scale)
  2145. {
  2146. if (mMediaSource && mMediaSource->pluginSupportsMediaTime())
  2147. {
  2148. F64 forward_step = mMediaSource->getCurrentTime() +
  2149. step_scale * mMediaSource->getDuration();
  2150. if (forward_step > mMediaSource->getDuration())
  2151. {
  2152. forward_step = mMediaSource->getDuration();
  2153. }
  2154. mMediaSource->seek(forward_step);
  2155. }
  2156. }
  2157. void LLViewerMediaImpl::setVolume(F32 volume)
  2158. {
  2159. mRequestedVolume = volume;
  2160. updateVolume();
  2161. }
  2162. void LLViewerMediaImpl::setMute(bool mute)
  2163. {
  2164. if (mute)
  2165. {
  2166. mPreviousVolume = mRequestedVolume;
  2167. setVolume(0.f);
  2168. }
  2169. else
  2170. {
  2171. setVolume(mPreviousVolume);
  2172. }
  2173. }
  2174. void LLViewerMediaImpl::updateVolume()
  2175. {
  2176. static LLCachedControl<F32> media_roll_off_min(gSavedSettings,
  2177. "MediaRollOffMin");
  2178. static LLCachedControl<F32> media_roll_off_max(gSavedSettings,
  2179. "MediaRollOffMax");
  2180. static LLCachedControl<F32> media_roll_off_rate(gSavedSettings,
  2181. "MediaRollOffRate");
  2182. if (mMediaSource)
  2183. {
  2184. // always scale the volume by the global media volume
  2185. F32 volume = mRequestedVolume * LLViewerMedia::getVolume();
  2186. if (mProximityCamera > 0.0)
  2187. {
  2188. if (mProximityCamera > (F64)media_roll_off_max)
  2189. {
  2190. volume = 0.f;
  2191. }
  2192. else if (mProximityCamera > (F64)media_roll_off_min)
  2193. {
  2194. // attenuated_volume = 1 / (roll_off_rate * (d - min))^2
  2195. // the +1 is there so that for distance 0 the volume stays the
  2196. // same
  2197. F64 adjusted_distance = mProximityCamera - media_roll_off_min;
  2198. F64 attenuation = 1.0 + media_roll_off_rate * adjusted_distance;
  2199. attenuation = 1.0 / (attenuation * attenuation);
  2200. // the attenuation multiplier should never be more than one
  2201. // since that would increase volume
  2202. volume = volume * llmin(1.0, attenuation);
  2203. }
  2204. }
  2205. if (sOnlyAudibleTextureID.isNull() ||
  2206. sOnlyAudibleTextureID == mTextureId)
  2207. {
  2208. mMediaSource->setVolume(volume);
  2209. }
  2210. else
  2211. {
  2212. mMediaSource->setVolume(0.f);
  2213. }
  2214. }
  2215. }
  2216. F32 LLViewerMediaImpl::getVolume()
  2217. {
  2218. return mRequestedVolume;
  2219. }
  2220. void LLViewerMediaImpl::focus(bool focus)
  2221. {
  2222. mHasFocus = focus;
  2223. if (mMediaSource)
  2224. {
  2225. // call focus just for the hell of it, even though this apopears to be
  2226. // a nop
  2227. mMediaSource->focus(focus);
  2228. #if 0 // Do not do this anymore: it actually clicks through now.
  2229. if (focus)
  2230. {
  2231. // spoof a mouse click to *actually* pass focus
  2232. mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN,
  2233. 1, 1, 0);
  2234. mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP,
  2235. 1, 1, 0);
  2236. }
  2237. #endif
  2238. }
  2239. }
  2240. bool LLViewerMediaImpl::hasFocus() const
  2241. {
  2242. // FIXME: This might be able to be a bit smarter by hooking into
  2243. // LLViewerMediaFocus, etc.
  2244. return mHasFocus;
  2245. }
  2246. void LLViewerMediaImpl::setHomeURL(const std::string& home_url,
  2247. const std::string& mime_type)
  2248. {
  2249. mHomeURL = home_url;
  2250. mHomeMimeType = mime_type;
  2251. }
  2252. std::string LLViewerMediaImpl::getCurrentMediaURL()
  2253. {
  2254. if (!mCurrentMediaURL.empty())
  2255. {
  2256. return mCurrentMediaURL;
  2257. }
  2258. return mMediaURL;
  2259. }
  2260. void LLViewerMediaImpl::setPageZoomFactor(F64 factor)
  2261. {
  2262. if (mMediaSource && factor != mZoomFactor)
  2263. {
  2264. mZoomFactor = factor;
  2265. mMediaSource->set_page_zoom_factor(factor);
  2266. }
  2267. }
  2268. void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button)
  2269. {
  2270. scaleMouse(&x, &y);
  2271. mLastMouseX = x;
  2272. mLastMouseY = y;
  2273. if (mMediaSource)
  2274. {
  2275. if (gDebugClicks)
  2276. {
  2277. llinfos << "Sending event Mouse Down to media" << llendl;
  2278. }
  2279. mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button,
  2280. x, y, mask);
  2281. }
  2282. }
  2283. void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button)
  2284. {
  2285. scaleMouse(&x, &y);
  2286. mLastMouseX = x;
  2287. mLastMouseY = y;
  2288. if (mMediaSource)
  2289. {
  2290. if (gDebugClicks)
  2291. {
  2292. llinfos << "Sending event Mouse Up to media" << llendl;
  2293. }
  2294. mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button,
  2295. x, y, mask);
  2296. }
  2297. }
  2298. void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask)
  2299. {
  2300. scaleMouse(&x, &y);
  2301. mLastMouseX = x;
  2302. mLastMouseY = y;
  2303. if (mMediaSource)
  2304. {
  2305. mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0,
  2306. x, y, mask);
  2307. }
  2308. }
  2309. //static
  2310. void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords,
  2311. S32* x, S32* y)
  2312. {
  2313. F32 texture_x = texture_coords.mV[VX];
  2314. F32 texture_y = texture_coords.mV[VY];
  2315. // Deal with repeating textures by wrapping the coordinates into the range
  2316. // [0.0, 1.0)
  2317. texture_x = fmodf(texture_x, 1.f);
  2318. if (texture_x < 0.f)
  2319. {
  2320. texture_x = 1.f + texture_x;
  2321. }
  2322. texture_y = fmodf(texture_y, 1.f);
  2323. if (texture_y < 0.f)
  2324. {
  2325. texture_y = 1.f + texture_y;
  2326. }
  2327. // Scale x and y to texel units.
  2328. *x = ll_round(texture_x * mMediaSource->getTextureWidth());
  2329. *y = ll_round((1.f - texture_y) * mMediaSource->getTextureHeight());
  2330. // Adjust for the difference between the actual texture height and the
  2331. // amount of the texture in use.
  2332. *y -= mMediaSource->getTextureHeight() - mMediaSource->getHeight();
  2333. }
  2334. void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask,
  2335. S32 button)
  2336. {
  2337. if (mMediaSource)
  2338. {
  2339. S32 x, y;
  2340. scaleTextureCoords(texture_coords, &x, &y);
  2341. mouseDown(x, y, mask, button);
  2342. }
  2343. }
  2344. void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask,
  2345. S32 button)
  2346. {
  2347. if (mMediaSource)
  2348. {
  2349. S32 x, y;
  2350. scaleTextureCoords(texture_coords, &x, &y);
  2351. mouseUp(x, y, mask, button);
  2352. }
  2353. }
  2354. void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask)
  2355. {
  2356. if (mMediaSource)
  2357. {
  2358. S32 x, y;
  2359. scaleTextureCoords(texture_coords, &x, &y);
  2360. mouseMove(x, y, mask);
  2361. }
  2362. }
  2363. void LLViewerMediaImpl::mouseDoubleClick(const LLVector2& texture_coords,
  2364. MASK mask)
  2365. {
  2366. if (mMediaSource)
  2367. {
  2368. S32 x, y;
  2369. scaleTextureCoords(texture_coords, &x, &y);
  2370. mouseDoubleClick(x, y, mask);
  2371. }
  2372. }
  2373. void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button)
  2374. {
  2375. scaleMouse(&x, &y);
  2376. mLastMouseX = x;
  2377. mLastMouseY = y;
  2378. if (mMediaSource)
  2379. {
  2380. if (gDebugClicks)
  2381. {
  2382. llinfos << "Sending event Mouse Double-click to media" << llendl;
  2383. }
  2384. mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK,
  2385. button, x, y, mask);
  2386. }
  2387. }
  2388. void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y,
  2389. MASK mask)
  2390. {
  2391. scaleMouse(&x, &y);
  2392. mLastMouseX = x;
  2393. mLastMouseY = y;
  2394. if (mMediaSource)
  2395. {
  2396. mMediaSource->scrollEvent(x, y, scroll_x, scroll_y, mask);
  2397. }
  2398. }
  2399. void LLViewerMediaImpl::onMouseCaptureLost()
  2400. {
  2401. if (mMediaSource)
  2402. {
  2403. if (gDebugClicks)
  2404. {
  2405. llinfos << "Sending event Mouse Up to media" << llendl;
  2406. }
  2407. mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0,
  2408. mLastMouseX, mLastMouseY, 0);
  2409. }
  2410. }
  2411. bool LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask)
  2412. {
  2413. // NOTE: this is called when the mouse is released when we have capture.
  2414. // Due to the way mouse coordinates are mapped to the object, we cannot
  2415. // use the x and y coordinates that come in with the event.
  2416. if (hasMouseCapture())
  2417. {
  2418. if (gDebugClicks)
  2419. {
  2420. llinfos << "Media lost mouse capture" << llendl;
  2421. }
  2422. // Release the mouse -- this will also send a mouseup to the media
  2423. gFocusMgr.setMouseCapture(NULL);
  2424. }
  2425. return true;
  2426. }
  2427. std::string LLViewerMediaImpl::getName() const
  2428. {
  2429. if (mMediaSource)
  2430. {
  2431. std::string name = mMediaSource->getMediaName();
  2432. const std::string& artist = mMediaSource->getArtist();
  2433. if (!artist.empty())
  2434. {
  2435. if (!name.empty())
  2436. {
  2437. name += " - ";
  2438. }
  2439. name += "Artist: " + artist;
  2440. }
  2441. return name;
  2442. }
  2443. return LLStringUtil::null;
  2444. }
  2445. void LLViewerMediaImpl::navigateBack()
  2446. {
  2447. if (mMediaSource)
  2448. {
  2449. mMediaSource->browse_back();
  2450. }
  2451. }
  2452. void LLViewerMediaImpl::navigateForward()
  2453. {
  2454. if (mMediaSource)
  2455. {
  2456. mMediaSource->browse_forward();
  2457. }
  2458. }
  2459. void LLViewerMediaImpl::navigateReload()
  2460. {
  2461. navigateTo(getCurrentMediaURL(), "", true);
  2462. }
  2463. void LLViewerMediaImpl::navigateHome()
  2464. {
  2465. bool rediscover_mimetype = mHomeMimeType.empty();
  2466. navigateTo(mHomeURL, mHomeMimeType, rediscover_mimetype);
  2467. }
  2468. void LLViewerMediaImpl::unload()
  2469. {
  2470. // Unload the media impl and clear its state.
  2471. destroyMediaSource();
  2472. resetPreviousMediaState();
  2473. mMediaURL.clear();
  2474. mMimeType.clear();
  2475. mCurrentMediaURL.clear();
  2476. mCurrentMimeType.clear();
  2477. }
  2478. void LLViewerMediaImpl::navigateTo(const std::string& url,
  2479. const std::string& mime_type,
  2480. bool rediscover_type,
  2481. bool server_request,
  2482. bool filter_url)
  2483. {
  2484. cancelMimeTypeProbe();
  2485. if (mMediaURL != url)
  2486. {
  2487. // Do not carry media play state across distinct URLs.
  2488. resetPreviousMediaState();
  2489. }
  2490. // Always set the current URL and MIME type.
  2491. mMediaURL = url;
  2492. mFilterURL = filter_url;
  2493. mMimeType = mime_type;
  2494. // Clear the current media URL, since it will no longer be correct.
  2495. mCurrentMediaURL.clear();
  2496. // if mime type discovery was requested, we'll need to do it when the media
  2497. // loads
  2498. mNavigateRediscoverType = rediscover_type;
  2499. // and if this was a server request, the navigate on load will also need to
  2500. // be one.
  2501. mNavigateServerRequest = server_request;
  2502. // An explicit navigate resets the "failed" flag.
  2503. mMediaSourceFailed = false;
  2504. if (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
  2505. {
  2506. // Helpful to have media urls in log file. Should not be spammy.
  2507. // Do not log the query parts
  2508. LLURI u(url);
  2509. std::string sanitized_url;
  2510. if (u.query().empty())
  2511. {
  2512. sanitized_url = url;
  2513. }
  2514. else
  2515. {
  2516. sanitized_url = u.scheme() + "://" + u.authority() + u.path();
  2517. }
  2518. llinfos << "NOT LOADING media id = " << mTextureId << " - url = "
  2519. << sanitized_url << " - mime_type = " << mime_type << llendl;
  2520. // This impl should not be loaded at this time.
  2521. LL_DEBUGS("PluginPriority") << std::hex << (intptr_t)this << std::dec
  2522. << "Not loading (PRIORITY_UNLOADED)"
  2523. << LL_ENDL;
  2524. }
  2525. else
  2526. {
  2527. navigateInternal();
  2528. }
  2529. }
  2530. void LLViewerMediaImpl::navigateInternal()
  2531. {
  2532. // Helpful to have media urls in log file. Should not be spammy.
  2533. // Do not log the query parts
  2534. LLURI u(mMediaURL);
  2535. std::string sanitized_url;
  2536. if (u.query().empty())
  2537. {
  2538. sanitized_url = mMediaURL;
  2539. }
  2540. else
  2541. {
  2542. sanitized_url = u.scheme() + "://" + u.authority() + u.path();
  2543. }
  2544. llinfos << "media id = " << mTextureId << " - url = " << sanitized_url
  2545. << " - mime_type = " << mMimeType << llendl;
  2546. if (mNavigateSuspended)
  2547. {
  2548. llwarns << "Deferring navigate." << llendl;
  2549. mNavigateSuspendedDeferred = true;
  2550. return;
  2551. }
  2552. if (!mMimeProbe.expired())
  2553. {
  2554. llwarns << "MIME type probe already in progress -- bailing out."
  2555. << llendl;
  2556. return;
  2557. }
  2558. if (mFilterURL && gSavedSettings.getBool("MediaEnableFilter") &&
  2559. // Do not filter login screens:
  2560. LLStartUp::isLoggedIn() && LLViewerMedia::filterMedia(this))
  2561. {
  2562. // Filter triggered: abort for now, navigateInternal() will potentially
  2563. // be called again (on callback, if a permission dialog was popped up).
  2564. return;
  2565. }
  2566. if (mNavigateServerRequest)
  2567. {
  2568. setNavState(MEDIANAVSTATE_SERVER_SENT);
  2569. }
  2570. else
  2571. {
  2572. setNavState(MEDIANAVSTATE_NONE);
  2573. }
  2574. // If the caller has specified a non-empty MIME type, look that up in our
  2575. // MIME types list. If we have a plugin for that MIME type, use that
  2576. // instead of attempting auto-discovery. This helps in supporting legacy
  2577. // media content where the server the media resides on returns a bogus MIME
  2578. // type but the parcel owner has correctly set the MIME type in the parcel
  2579. // media settings.
  2580. if (!mMimeType.empty() && mMimeType != LLMIMETypes::getDefaultMimeType())
  2581. {
  2582. std::string plugin_basename = LLMIMETypes::implType(mMimeType);
  2583. if (!plugin_basename.empty())
  2584. {
  2585. // We have a plugin for this mime type
  2586. mNavigateRediscoverType = false;
  2587. }
  2588. }
  2589. if (mNavigateRediscoverType)
  2590. {
  2591. LLURI uri(mMediaURL);
  2592. std::string scheme = uri.scheme();
  2593. if (scheme.empty() || "http" == scheme || "https" == scheme)
  2594. {
  2595. gCoros.launch("LLViewerMediaImpl::mimeDiscoveryCoro",
  2596. boost::bind(&LLViewerMediaImpl::mimeDiscoveryCoro,
  2597. this, mMediaURL));
  2598. }
  2599. else if ("data" == scheme || "file" == scheme || "about" == scheme)
  2600. {
  2601. // FIXME: figure out how to really discover the type for these
  2602. // schemes.
  2603. // We use "data" internally for a text/html url for loading the
  2604. // login screen
  2605. if (initializeMedia(HTTP_CONTENT_TEXT_HTML))
  2606. {
  2607. loadURI();
  2608. }
  2609. }
  2610. else
  2611. {
  2612. // This catches 'rtsp://' urls
  2613. if (initializeMedia(scheme))
  2614. {
  2615. loadURI();
  2616. }
  2617. }
  2618. }
  2619. else if (initializeMedia(mMimeType))
  2620. {
  2621. loadURI();
  2622. }
  2623. else
  2624. {
  2625. llwarns << "Could not navigate to '" << mMediaURL
  2626. << "' as there is no media type for: " << mMimeType << llendl;
  2627. }
  2628. }
  2629. void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url)
  2630. {
  2631. // Increment our refcount so that we do not go away while the coroutine is
  2632. // active.
  2633. ref();
  2634. LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
  2635. adapter(new LLCoreHttpUtil::HttpCoroutineAdapter("mimeDiscoveryCoro"));
  2636. mMimeProbe = adapter;
  2637. LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions);
  2638. // We only need the MIME type (e.g. text/html), and following redirects can
  2639. // takes several seconds with some sites (e.g. the SL Marketplace).
  2640. options->setFollowRedirects(false);
  2641. options->setHeadersOnly(true);
  2642. LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders);
  2643. headers->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
  2644. headers->append(HTTP_OUT_HEADER_COOKIE, "");
  2645. LLSD result = adapter->getRawAndSuspend(url, options, headers);
  2646. mMimeProbe.reset();
  2647. LLCore::HttpStatus status =
  2648. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  2649. if (!status)
  2650. {
  2651. // Demoted from warning to debug message, since not an issue. HB
  2652. LL_DEBUGS("Media") << "Could not retrieve media headers: "
  2653. << status.toString() << LL_ENDL;
  2654. }
  2655. // If there is only a single ref count outstanding it will be the one we
  2656. // took out above andwe can skip the rest of this routine.
  2657. if (getNumRefs() > 1)
  2658. {
  2659. const LLSD& httpres =
  2660. result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
  2661. const LLSD& header =
  2662. httpres[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
  2663. std::string mime_type = header[HTTP_IN_HEADER_CONTENT_TYPE].asString();
  2664. size_t i = mime_type.find_first_of(";");
  2665. mime_type = mime_type.substr(0, i);
  2666. // We now no longer check the error code returned from the probe. If we
  2667. // have a mime type, use it, if not default to the web plugin and let
  2668. // it handle error reporting.
  2669. if (mime_type.empty())
  2670. {
  2671. LL_DEBUGS("Media") << "Mime type empty or missing from header"
  2672. << LL_ENDL;
  2673. // Some sites do not return any content-type header at all. Treat
  2674. // an empty mime type as text/html.
  2675. mime_type = HTTP_CONTENT_TEXT_HTML;
  2676. }
  2677. LL_DEBUGS("Media") << "Status: " << status.getType()
  2678. << " - Mime type: " << mime_type << LL_ENDL;
  2679. // Note: the call to initializeMedia may disconnect the responder,
  2680. // which would clear mMediaImpl.
  2681. if (!mime_type.empty())
  2682. {
  2683. if (initializeMedia(mime_type))
  2684. {
  2685. loadURI();
  2686. }
  2687. }
  2688. }
  2689. else
  2690. {
  2691. LL_DEBUGS("Media") << "LLViewerMediaImpl to be released." << LL_ENDL;
  2692. }
  2693. unref();
  2694. }
  2695. void LLViewerMediaImpl::navigateStop()
  2696. {
  2697. if (mMediaSource)
  2698. {
  2699. mMediaSource->browse_stop();
  2700. }
  2701. }
  2702. bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
  2703. {
  2704. bool result = false;
  2705. if (mMediaSource)
  2706. {
  2707. // FIXME: THIS IS SO WRONG.
  2708. // Menu keys should be handled by the menu system and not passed to UI
  2709. // elements, but this is how LLTextEditor and LLLineEditor do it...
  2710. if ((MASK_CONTROL & mask) && (key == 'C' || key == 'V' || key == 'X'))
  2711. {
  2712. result = true;
  2713. }
  2714. if (!result)
  2715. {
  2716. if (LLView::sDebugKeys)
  2717. {
  2718. llinfos << "Key handling passed to the media plugin" << llendl;
  2719. }
  2720. LLSD native_key_data = gWindowp->getNativeKeyData();
  2721. result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN,
  2722. key, mask, native_key_data);
  2723. }
  2724. }
  2725. return result;
  2726. }
  2727. bool LLViewerMediaImpl::handleKeyUpHere(KEY key, MASK mask)
  2728. {
  2729. bool result = false;
  2730. if (mMediaSource)
  2731. {
  2732. // FIXME: THIS IS SO WRONG.
  2733. // Menu keys should be handled by the menu system and not passed to UI
  2734. // elements, but this is how LLTextEditor and LLLineEditor do it...
  2735. if (MASK_CONTROL & mask)
  2736. {
  2737. if (key == 'C')
  2738. {
  2739. mMediaSource->copy();
  2740. result = true;
  2741. }
  2742. else if (key == 'V')
  2743. {
  2744. mMediaSource->paste();
  2745. result = true;
  2746. }
  2747. else if (key == 'X')
  2748. {
  2749. mMediaSource->cut();
  2750. result = true;
  2751. }
  2752. }
  2753. if (!result)
  2754. {
  2755. LLSD native_key_data = gWindowp->getNativeKeyData();
  2756. result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP,
  2757. key, mask, native_key_data);
  2758. }
  2759. }
  2760. return result;
  2761. }
  2762. bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
  2763. {
  2764. if (mMediaSource && gKeyboardp)
  2765. {
  2766. // Only accept 'printable' characters, sigh...
  2767. if (uni_char >= 32 && // discard 'control' characters
  2768. uni_char != 127) // SDL thinks this is 'delete'
  2769. {
  2770. if (LLView::sDebugKeys)
  2771. {
  2772. llinfos << "Key handling passed to the media plugin" << llendl;
  2773. }
  2774. LLSD native_key_data = gWindowp->getNativeKeyData();
  2775. mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)),
  2776. gKeyboardp->currentMask(false),
  2777. native_key_data);
  2778. }
  2779. }
  2780. return false;
  2781. }
  2782. bool LLViewerMediaImpl::canNavigateForward()
  2783. {
  2784. return mMediaSource && mMediaSource->getHistoryForwardAvailable();
  2785. }
  2786. bool LLViewerMediaImpl::canNavigateBack()
  2787. {
  2788. return mMediaSource && mMediaSource->getHistoryBackAvailable();
  2789. }
  2790. void LLViewerMediaImpl::update()
  2791. {
  2792. LL_FAST_TIMER(FTM_MEDIA_DO_UPDATE);
  2793. if (!mMediaSource &&
  2794. // do not load sources doing a MIME type probe.
  2795. mMimeProbe.expired() &&
  2796. // or sources media source should not be loaded.
  2797. mPriority != LLPluginClassMedia::PRIORITY_UNLOADED &&
  2798. // do not load new instances that are at PRIORITY_SLIDESHOW or below,
  2799. // they are just kept around to preserve state.
  2800. mPriority > LLPluginClassMedia::PRIORITY_SLIDESHOW)
  2801. {
  2802. // This media may need to be loaded.
  2803. if (sMediaCreateTimer.hasExpired())
  2804. {
  2805. LL_DEBUGS("PluginPriority") << this
  2806. << ": creating media based on timer expiration"
  2807. << LL_ENDL;
  2808. createMediaSource();
  2809. sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY);
  2810. }
  2811. else
  2812. {
  2813. LL_DEBUGS("PluginPriority") << this
  2814. << ": NOT creating media (waiting on timer)"
  2815. << LL_ENDL;
  2816. }
  2817. }
  2818. else
  2819. {
  2820. updateVolume();
  2821. }
  2822. if (!mMediaSource)
  2823. {
  2824. return;
  2825. }
  2826. // Make sure a navigate does not happen during the idle: it can cause
  2827. // mMediaSource to get destroyed, which can cause a crash.
  2828. setNavigateSuspended(true);
  2829. mMediaSource->idle();
  2830. setNavigateSuspended(false);
  2831. if (!mMediaSource)
  2832. {
  2833. return;
  2834. }
  2835. if (mMediaSource->isPluginExited())
  2836. {
  2837. resetPreviousMediaState();
  2838. destroyMediaSource();
  2839. return;
  2840. }
  2841. if (!mMediaSource->textureValid() || mSuspendUpdates || !mVisible)
  2842. {
  2843. return;
  2844. }
  2845. LLViewerMediaTexture* media_tex;
  2846. U8* data;
  2847. S32 data_width, data_height, x_pos, y_pos, width, height;
  2848. if (!preMediaTexUpdate(media_tex, data, data_width, data_height, x_pos,
  2849. y_pos, width, height))
  2850. {
  2851. return;
  2852. }
  2853. static LLCachedControl<bool> use_worker(gSavedSettings,
  2854. "GLWorkerUseForMedia");
  2855. bool can_queue = use_worker && LLImageGLThread::sEnabled && gMainloopWorkp;
  2856. if (can_queue)
  2857. {
  2858. mTextureUpdatePending = true;
  2859. // Protect textures from deletion while active on bg queue
  2860. ref();
  2861. media_tex->ref();
  2862. // Push update to the worker thread
  2863. if (gMainloopWorkp->postTo(gImageQueuep,
  2864. [=]() // Work done on worker thread
  2865. {
  2866. doMediaTexUpdate(media_tex, data,
  2867. data_width,
  2868. data_height,
  2869. x_pos, y_pos,
  2870. width, height, true);
  2871. },
  2872. [=]() // Callback to main thread
  2873. {
  2874. mTextureUpdatePending = false;
  2875. media_tex->unref();
  2876. unref();
  2877. }))
  2878. {
  2879. return; // Success
  2880. }
  2881. // Failed (gImageQueuep closed): fallback to update on main thread
  2882. mTextureUpdatePending = false;
  2883. media_tex->unref();
  2884. unref();
  2885. }
  2886. {
  2887. LL_FAST_TIMER(FTM_MEDIA_SET_SUBIMAGE);
  2888. // Update on the main thread
  2889. doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos,
  2890. y_pos, width, height, false);
  2891. }
  2892. }
  2893. bool LLViewerMediaImpl::preMediaTexUpdate(LLViewerMediaTexture*& media_tex,
  2894. U8*& data, S32& data_width,
  2895. S32& data_height, S32& x_pos,
  2896. S32& y_pos, S32& width, S32& height)
  2897. {
  2898. LL_TRACY_TIMER(TRC_MEDIA_PRE_UPDATE);
  2899. if (mTextureUpdatePending)
  2900. {
  2901. return false;
  2902. }
  2903. bool success = false;
  2904. media_tex = updateMediaImage();
  2905. if (media_tex && mMediaSource)
  2906. {
  2907. LLRect dirty_rect;
  2908. S32 media_width = mMediaSource->getTextureWidth();
  2909. S32 media_height = mMediaSource->getTextureHeight();
  2910. // Since we are updating this texture, we know it is playing. Tell the
  2911. // texture to do its replacement magic so it gets rendered.
  2912. media_tex->setPlaying(true);
  2913. if (mMediaSource->getDirty(&dirty_rect))
  2914. {
  2915. // Constrain the dirty rect to be inside the texture
  2916. x_pos = llmax(dirty_rect.mLeft, 0);
  2917. y_pos = llmax(dirty_rect.mBottom, 0);
  2918. width = llmin(dirty_rect.mRight, media_width) - x_pos;
  2919. height = llmin(dirty_rect.mTop, media_height) - y_pos;
  2920. if (width > 0 && height > 0)
  2921. {
  2922. LL_FAST_TIMER(FTM_MEDIA_GET_DATA);
  2923. data = mMediaSource->getBitsData();
  2924. data_width = mMediaSource->getWidth();
  2925. data_height = mMediaSource->getHeight();
  2926. // This will be true when data is ready to be copied to GL
  2927. success = data != NULL;
  2928. }
  2929. }
  2930. mMediaSource->resetDirty();
  2931. }
  2932. return success;
  2933. }
  2934. void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex,
  2935. U8* data, S32 data_width,
  2936. S32 data_height, S32 x_pos, S32 y_pos,
  2937. S32 width, S32 height, bool sync)
  2938. {
  2939. LL_TRACY_TIMER(TRC_MEDIA_TEX_UPDATE);
  2940. // Prevents media source tear-down during update
  2941. mLock.lock();
  2942. static LLCachedControl<bool> recreate(gSavedSettings,
  2943. "RecreateMediaGLTexOnUpdate");
  2944. bool do_recreate = recreate;
  2945. U32 tex_name = media_tex->getTexName();
  2946. if (!tex_name)
  2947. {
  2948. do_recreate = true;
  2949. }
  2950. // Wrap 'data' in an LLImageRaw but do NOT make a copy.
  2951. LLPointer<LLImageRaw> raw = new LLImageRaw(data, media_tex->getWidth(),
  2952. media_tex->getHeight(),
  2953. media_tex->getComponents(),
  2954. true);
  2955. // Recreating the GL texture at each media update is wasteful but might be
  2956. // needed when GL calls are blocking in some poor OpenGL implementations.
  2957. if (do_recreate)
  2958. {
  2959. media_tex->createGLTexture(0, raw, 0, true, true, &tex_name);
  2960. }
  2961. // Copy just the subimage covered by the image raw to GL
  2962. media_tex->setSubImage(data, data_width, data_height, x_pos, y_pos, width,
  2963. height, tex_name);
  2964. if (sync)
  2965. {
  2966. media_tex->getGLImage()->syncToMainThread(tex_name);
  2967. }
  2968. else
  2969. {
  2970. media_tex->getGLImage()->syncTexName(tex_name);
  2971. }
  2972. // Release the data pointer before freeing raw so LLImageRaw destructor
  2973. // does not free memory at data pointer.
  2974. raw->releaseData();
  2975. mLock.unlock();
  2976. }
  2977. LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage()
  2978. {
  2979. if (mTextureId.isNull())
  2980. {
  2981. // The code that created this instance will read from the plugin's bits
  2982. return NULL;
  2983. }
  2984. if (!mMediaSource)
  2985. {
  2986. // Not ready for updating
  2987. return NULL;
  2988. }
  2989. LLViewerMediaTexture* media_tex =
  2990. LLViewerTextureManager::getMediaTexture(mTextureId);
  2991. if (!media_tex)
  2992. {
  2993. llwarns << "Could not find media texture " << mTextureId << llendl;
  2994. return NULL;
  2995. }
  2996. if (mNeedsNewTexture ||
  2997. media_tex->getWidth() != mMediaSource->getTextureWidth() ||
  2998. media_tex->getHeight() != mMediaSource->getTextureHeight() ||
  2999. mTextureUsedWidth != mMediaSource->getWidth() ||
  3000. mTextureUsedHeight != mMediaSource->getHeight())
  3001. {
  3002. llinfos << "Initializing media placeholder with movie image id: "
  3003. << mTextureId << llendl;
  3004. U16 texture_width = mMediaSource->getTextureWidth();
  3005. U16 texture_height = mMediaSource->getTextureHeight();
  3006. S8 texture_depth = mMediaSource->getTextureDepth();
  3007. // MEDIAOPT: check to see if size actually changed before doing work
  3008. media_tex->destroyGLTexture();
  3009. // MEDIAOPT: seems insane that we actually have to make an imageraw
  3010. // then immediately discard it
  3011. LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width,
  3012. texture_height,
  3013. texture_depth);
  3014. raw->clear(U8(mBackgroundColor.mV[VX] * 255.f),
  3015. U8(mBackgroundColor.mV[VY] * 255.f),
  3016. U8(mBackgroundColor.mV[VZ] * 255.f), 255);
  3017. // Ask media source for correct GL image format constants
  3018. media_tex->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
  3019. mMediaSource->getTextureFormatPrimary(),
  3020. mMediaSource->getTextureFormatType(),
  3021. mMediaSource->getTextureFormatSwapBytes());
  3022. media_tex->createGLTexture(0, raw); // 0 discard
  3023. mNeedsNewTexture = false;
  3024. // If the amount of the texture being drawn by the media goes down in
  3025. // either width or height, recreate the texture to avoid leaving parts
  3026. // of the old image behind.
  3027. mTextureUsedWidth = mMediaSource->getWidth();
  3028. mTextureUsedHeight = mMediaSource->getHeight();
  3029. }
  3030. return media_tex;
  3031. }
  3032. void LLViewerMediaImpl::setVisible(bool visible)
  3033. {
  3034. mVisible = visible;
  3035. if (visible)
  3036. {
  3037. if (mMediaSource && mMediaSource->isPluginExited())
  3038. {
  3039. destroyMediaSource();
  3040. }
  3041. if (!mMediaSource)
  3042. {
  3043. createMediaSource();
  3044. }
  3045. }
  3046. }
  3047. void LLViewerMediaImpl::mouseCapture()
  3048. {
  3049. if (gDebugClicks)
  3050. {
  3051. llinfos << "Media gained mouse capture" << llendl;
  3052. }
  3053. gFocusMgr.setMouseCapture(this);
  3054. }
  3055. void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y)
  3056. {
  3057. #if 0
  3058. S32 media_width, media_height;
  3059. S32 texture_width, texture_height;
  3060. getMediaSize(&media_width, &media_height);
  3061. getTextureSize(&texture_width, &texture_height);
  3062. S32 y_delta = texture_height - media_height;
  3063. *mouse_y -= y_delta;
  3064. #endif
  3065. }
  3066. bool LLViewerMediaImpl::isMediaTimeBased()
  3067. {
  3068. return mMediaSource && mMediaSource->pluginSupportsMediaTime();
  3069. }
  3070. bool LLViewerMediaImpl::isMediaPlaying()
  3071. {
  3072. bool result = false;
  3073. if (mMediaSource)
  3074. {
  3075. EMediaStatus status = mMediaSource->getStatus();
  3076. if (status == MEDIA_PLAYING || status == MEDIA_LOADING)
  3077. {
  3078. result = true;
  3079. }
  3080. }
  3081. return result;
  3082. }
  3083. bool LLViewerMediaImpl::isMediaPaused()
  3084. {
  3085. return mMediaSource && mMediaSource->getStatus() == MEDIA_PAUSED;
  3086. }
  3087. bool LLViewerMediaImpl::hasMedia()
  3088. {
  3089. return mMediaSource != NULL;
  3090. }
  3091. void LLViewerMediaImpl::resetPreviousMediaState()
  3092. {
  3093. mPreviousMediaState = MEDIA_NONE;
  3094. mPreviousMediaTime = 0.f;
  3095. }
  3096. void LLViewerMediaImpl::setDisabled(bool disabled, bool forcePlayOnEnable)
  3097. {
  3098. if (mIsDisabled != disabled)
  3099. {
  3100. // Only do this on actual state transitions.
  3101. mIsDisabled = disabled;
  3102. if (mIsDisabled)
  3103. {
  3104. // We just disabled this media. Clear all state.
  3105. unload();
  3106. }
  3107. else
  3108. {
  3109. // We just (re)enabled this media. Do a navigate if auto-play is in
  3110. // order.
  3111. if (isAutoPlayable() || forcePlayOnEnable)
  3112. {
  3113. navigateTo(mMediaEntryURL, "", true, true);
  3114. }
  3115. }
  3116. }
  3117. }
  3118. bool LLViewerMediaImpl::isForcedUnloaded() const
  3119. {
  3120. if (mIsMuted || mMediaSourceFailed || mIsDisabled ||
  3121. // If this media's class is not supposed to be shown, unload
  3122. !shouldShowBasedOnClass())
  3123. {
  3124. return true;
  3125. }
  3126. return false;
  3127. }
  3128. bool LLViewerMediaImpl::isPlayable() const
  3129. {
  3130. if (isForcedUnloaded())
  3131. {
  3132. // All of the forced-unloaded criteria also imply not playable.
  3133. return false;
  3134. }
  3135. if (((LLViewerMediaImpl*)this)->hasMedia())
  3136. {
  3137. // Anything that is already playing is, by definition, playable.
  3138. return true;
  3139. }
  3140. if (!mMediaURL.empty())
  3141. {
  3142. // If something has navigated the instance, it's ready to be played.
  3143. return true;
  3144. }
  3145. return false;
  3146. }
  3147. void select_file_callback(HBFileSelector::ELoadFilter type,
  3148. std::string& filename, void* user_data)
  3149. {
  3150. LLPluginClassMedia* plugin = (LLPluginClassMedia*)user_data;
  3151. if (plugin) // *TODO: Add a check about the plugin's existence...
  3152. {
  3153. plugin->sendPickFileResponse(filename);
  3154. }
  3155. }
  3156. void select_files_callback(HBFileSelector::ELoadFilter type,
  3157. std::deque<std::string>& files, void* user_data)
  3158. {
  3159. LLPluginClassMedia* plugin = (LLPluginClassMedia*)user_data;
  3160. if (plugin) // *TODO: Add a check about the plugin's existence...
  3161. {
  3162. std::vector<std::string> file_list;
  3163. while (!files.empty())
  3164. {
  3165. file_list.push_back(files.front());
  3166. files.pop_front();
  3167. }
  3168. plugin->sendPickFileResponse(file_list);
  3169. }
  3170. }
  3171. void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin,
  3172. LLPluginClassMediaOwner::EMediaEvent event)
  3173. {
  3174. if (!plugin) return;
  3175. bool pass_through = true;
  3176. switch (event)
  3177. {
  3178. case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
  3179. {
  3180. std::string url = plugin->getClickURL();
  3181. LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, URI: "
  3182. << url << LL_ENDL;
  3183. std::string nav_type = plugin->getClickNavType();
  3184. LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser);
  3185. break;
  3186. }
  3187. case MEDIA_EVENT_CLICK_LINK_HREF:
  3188. {
  3189. // Retrieve the event parameters
  3190. std::string url = plugin->getClickURL();
  3191. std::string target =
  3192. plugin->isOverrideClickTarget() ? plugin->getOverrideClickTarget()
  3193. : plugin->getClickTarget();
  3194. // loadURL now handles distinguishing between _blank, _external,
  3195. // and other named targets.
  3196. LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_HREF, target: "
  3197. << target << " - URI: " << url << LL_ENDL;
  3198. LLWeb::loadURL(url, target);
  3199. break;
  3200. }
  3201. case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
  3202. {
  3203. // The plugin failed to load properly. Make sure the timer does not
  3204. // retry. *TODO: maybe mark this plugin as not loadable somehow ?
  3205. mMediaSourceFailed = true;
  3206. // Reset the last known state of the media to defaults.
  3207. resetPreviousMediaState();
  3208. // *TODO: may want a different message for this case ?
  3209. LLSD args;
  3210. args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType);
  3211. gNotifications.add("MediaPluginFailed", args);
  3212. break;
  3213. }
  3214. case MEDIA_EVENT_PLUGIN_FAILED:
  3215. {
  3216. // The plugin crashed.
  3217. mMediaSourceFailed = true;
  3218. // Reset the last known state of the media to defaults.
  3219. resetPreviousMediaState();
  3220. #if 0 // SJB: This is getting called every frame if the plugin fails to
  3221. // load, continuously respawining the alert !
  3222. LLSD args;
  3223. args["PLUGIN"] = LLMIMETypes::implType(mMimeType);
  3224. gNotifications.add("MediaPluginFailed", args);
  3225. #endif
  3226. break;
  3227. }
  3228. case MEDIA_EVENT_CURSOR_CHANGED:
  3229. {
  3230. std::string cursor = plugin->getCursorName();
  3231. LL_DEBUGS("Media") << "MEDIA_EVENT_CURSOR_CHANGED, new cursor is: "
  3232. << cursor << LL_ENDL;
  3233. if (cursor == "ibeam")
  3234. {
  3235. mLastSetCursor = UI_CURSOR_IBEAM;
  3236. }
  3237. else if (cursor == "splith")
  3238. {
  3239. mLastSetCursor = UI_CURSOR_SIZEWE;
  3240. }
  3241. else if (cursor == "splitv")
  3242. {
  3243. mLastSetCursor = UI_CURSOR_SIZENS;
  3244. }
  3245. else if (cursor == "hand")
  3246. {
  3247. mLastSetCursor = UI_CURSOR_HAND;
  3248. }
  3249. else
  3250. {
  3251. // For anything else, default to the arrow
  3252. mLastSetCursor = UI_CURSOR_ARROW;
  3253. }
  3254. break;
  3255. }
  3256. case LLViewerMediaObserver::MEDIA_EVENT_FILE_DOWNLOAD:
  3257. {
  3258. // *TODO: allow downloading by sending the file URL to the system
  3259. // browser
  3260. LL_DEBUGS("Media") << "MEDIA_EVENT_FILE_DOWNLOAD, filename is: "
  3261. << plugin->getFileDownloadFilename() << LL_ENDL;
  3262. gNotifications.add("MediaFileDownloadUnsupported");
  3263. pass_through = false; // Do not chain this event !
  3264. break;
  3265. }
  3266. case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN:
  3267. {
  3268. LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: "
  3269. << plugin->getNavigateURI() << LL_ENDL;
  3270. if (getNavState() == MEDIANAVSTATE_SERVER_SENT)
  3271. {
  3272. setNavState(MEDIANAVSTATE_SERVER_BEGUN);
  3273. }
  3274. else
  3275. {
  3276. setNavState(MEDIANAVSTATE_BEGUN);
  3277. }
  3278. break;
  3279. }
  3280. case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
  3281. {
  3282. LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: "
  3283. << plugin->getNavigateURI() << LL_ENDL;
  3284. std::string url = plugin->getNavigateURI();
  3285. if (getNavState() == MEDIANAVSTATE_BEGUN)
  3286. {
  3287. if (mCurrentMediaURL == url)
  3288. {
  3289. // This is a navigate that takes us to the same url as the
  3290. // previous navigate.
  3291. setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS);
  3292. }
  3293. else
  3294. {
  3295. mCurrentMediaURL = url;
  3296. setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED);
  3297. }
  3298. }
  3299. else if (getNavState() == MEDIANAVSTATE_SERVER_BEGUN)
  3300. {
  3301. mCurrentMediaURL = url;
  3302. setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED);
  3303. }
  3304. // all other cases need to leave the state alone.
  3305. break;
  3306. }
  3307. case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED:
  3308. {
  3309. LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: "
  3310. << plugin->getLocation() << LL_ENDL;
  3311. std::string url = plugin->getLocation();
  3312. if (getNavState() == MEDIANAVSTATE_BEGUN)
  3313. {
  3314. if (mCurrentMediaURL == url)
  3315. {
  3316. // This is a navigate that takes us to the same url as the
  3317. // previous navigate.
  3318. setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS);
  3319. }
  3320. else
  3321. {
  3322. mCurrentMediaURL = url;
  3323. setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED);
  3324. }
  3325. }
  3326. else if (getNavState() == MEDIANAVSTATE_SERVER_BEGUN)
  3327. {
  3328. mCurrentMediaURL = url;
  3329. setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED);
  3330. }
  3331. else
  3332. {
  3333. bool internal_nav = false;
  3334. if (url != mCurrentMediaURL)
  3335. {
  3336. // Check if it is internal navigation. Note: not sure if we
  3337. // should detect internal navigations as 'address change',
  3338. // but they are not redirects and do not cause
  3339. // NAVIGATE_BEGIN (also see SL-1005).
  3340. size_t pos = url.find("#");
  3341. if (pos != std::string::npos)
  3342. {
  3343. // Assume that new link always have '#', so this is
  3344. // either transfer from 'link#1' to 'link#2' or from
  3345. // link to 'link#2'; filter out cases like
  3346. // 'redirect?link'
  3347. std::string base_url = url.substr(0, pos);
  3348. if (mCurrentMediaURL.find(base_url) == 0)
  3349. {
  3350. // Base link did not change
  3351. internal_nav = true;
  3352. }
  3353. }
  3354. }
  3355. if (internal_nav)
  3356. {
  3357. // Internal navigation by '#'
  3358. mCurrentMediaURL = url;
  3359. setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED);
  3360. }
  3361. else
  3362. {
  3363. // Do not track redirects.
  3364. setNavState(MEDIANAVSTATE_NONE);
  3365. }
  3366. }
  3367. break;
  3368. }
  3369. case LLViewerMediaObserver::MEDIA_EVENT_PICK_FILE_REQUEST:
  3370. {
  3371. // Display a file(s) selector
  3372. if (plugin->getIsMultipleFilePick())
  3373. {
  3374. HBFileSelector::loadFiles(HBFileSelector::FFLOAD_ALL,
  3375. select_files_callback, plugin);
  3376. }
  3377. else
  3378. {
  3379. HBFileSelector::loadFile(HBFileSelector::FFLOAD_ALL,
  3380. select_file_callback, plugin);
  3381. }
  3382. break;
  3383. }
  3384. case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST:
  3385. {
  3386. std::string host = plugin->getAuthURL();
  3387. size_t i = host.find("://");
  3388. if (i != std::string::npos)
  3389. {
  3390. host = host.substr(i + 3);
  3391. }
  3392. i = host.find("/");
  3393. if (i != std::string::npos)
  3394. {
  3395. host = host.substr(0, i);
  3396. }
  3397. const std::string& realm = plugin->getAuthRealm();
  3398. llinfos << "Spawning authentication request dialog for host: "
  3399. << host << " - Realm: " << realm << " - Media Id: "
  3400. << mTextureId << llendl;
  3401. HBFloaterUserAuth::request(host, realm, mTextureId,
  3402. LLViewerMedia::onAuthSubmit);
  3403. pass_through = false; // Do not chain this event !
  3404. break;
  3405. }
  3406. case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST:
  3407. {
  3408. std::string uuid = plugin->getClickUUID();
  3409. llinfos << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << llendl;
  3410. if (!uuid.empty())
  3411. {
  3412. // This close request is directed at another instance
  3413. pass_through = false;
  3414. // *TODO: LLFloaterMediaBrowser::closeRequest(uuid);
  3415. }
  3416. break;
  3417. }
  3418. case LLViewerMediaObserver::MEDIA_EVENT_GEOMETRY_CHANGE:
  3419. {
  3420. std::string uuid = plugin->getClickUUID();
  3421. llinfos << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << llendl;
  3422. if (uuid.empty())
  3423. {
  3424. // This geometry change request is directed at this instance,
  3425. // let it fall through.
  3426. }
  3427. else
  3428. {
  3429. // This request is directed at another instance
  3430. pass_through = false;
  3431. #if 0 // *TODO:
  3432. LLFloaterMediaBrowser::geometryChanged(uuid,
  3433. plugin->getGeometryX(),
  3434. plugin->getGeometryY(),
  3435. plugin->getGeometryWidth(),
  3436. plugin->getGeometryHeight());
  3437. #endif
  3438. }
  3439. break;
  3440. }
  3441. default:
  3442. {
  3443. }
  3444. }
  3445. if (pass_through)
  3446. {
  3447. // Just chain the event to observers.
  3448. emitEvent(plugin, event);
  3449. }
  3450. }
  3451. //virtual
  3452. void LLViewerMediaImpl::cut()
  3453. {
  3454. if (mMediaSource)
  3455. {
  3456. mMediaSource->cut();
  3457. }
  3458. }
  3459. //virtual
  3460. bool LLViewerMediaImpl::canCut() const
  3461. {
  3462. return mMediaSource && mMediaSource->canCut();
  3463. }
  3464. //virtual
  3465. void LLViewerMediaImpl::copy()
  3466. {
  3467. if (mMediaSource)
  3468. {
  3469. mMediaSource->copy();
  3470. }
  3471. }
  3472. //virtual
  3473. bool LLViewerMediaImpl::canCopy() const
  3474. {
  3475. return mMediaSource && mMediaSource->canCopy();
  3476. }
  3477. //virtual
  3478. void LLViewerMediaImpl::paste()
  3479. {
  3480. if (mMediaSource)
  3481. {
  3482. mMediaSource->paste();
  3483. }
  3484. }
  3485. //virtual
  3486. bool LLViewerMediaImpl::canPaste() const
  3487. {
  3488. return mMediaSource && mMediaSource->canPaste();
  3489. }
  3490. void LLViewerMediaImpl::setBackgroundColor(LLColor4 color)
  3491. {
  3492. mBackgroundColor = color;
  3493. if (mMediaSource)
  3494. {
  3495. mMediaSource->setBackgroundColor(mBackgroundColor);
  3496. }
  3497. }
  3498. void LLViewerMediaImpl::setNavState(EMediaNavState state)
  3499. {
  3500. mMediaNavState = state;
  3501. LL_DEBUGS("Media") << "Setting nav state to: ";
  3502. std::string state_str;
  3503. switch (state)
  3504. {
  3505. case MEDIANAVSTATE_NONE:
  3506. state_str = "MEDIANAVSTATE_NONE";
  3507. break;
  3508. case MEDIANAVSTATE_BEGUN:
  3509. state_str = "MEDIANAVSTATE_BEGUN";
  3510. break;
  3511. case MEDIANAVSTATE_FIRST_LOCATION_CHANGED:
  3512. state_str = "MEDIANAVSTATE_FIRST_LOCATION_CHANGED";
  3513. break;
  3514. case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS:
  3515. state_str = "MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS";
  3516. break;
  3517. case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED:
  3518. state_str = "MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED";
  3519. break;
  3520. case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS:
  3521. state_str = "MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS";
  3522. break;
  3523. case MEDIANAVSTATE_SERVER_SENT:
  3524. state_str = "MEDIANAVSTATE_SERVER_SENT";
  3525. break;
  3526. case MEDIANAVSTATE_SERVER_BEGUN:
  3527. state_str = "MEDIANAVSTATE_SERVER_BEGUN";
  3528. break;
  3529. case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED:
  3530. state_str = "MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED";
  3531. break;
  3532. case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED:
  3533. state_str = "MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED";
  3534. }
  3535. LL_CONT << state_str << LL_ENDL;
  3536. }
  3537. void LLViewerMediaImpl::calculateInterest()
  3538. {
  3539. LL_FAST_TIMER(FTM_MEDIA_CALCULATE_INTEREST);
  3540. LLViewerMediaTexture* texture =
  3541. LLViewerTextureManager::findMediaTexture(mTextureId);
  3542. if (texture)
  3543. {
  3544. mInterest = texture->getMaxVirtualSize();
  3545. }
  3546. else
  3547. {
  3548. // This will be a relatively common case now, since it will always be
  3549. // true for unloaded media.
  3550. mInterest = 0.f;
  3551. }
  3552. // Calculate distance from the avatar, for use in the proximity
  3553. // calculation.
  3554. mProximityDistance = 0.f;
  3555. mProximityCamera = 0.f;
  3556. if (!mObjectList.empty())
  3557. {
  3558. // Just use the first object in the list. We could go through the list
  3559. // and find the closest object, but this should work well enough.
  3560. std::list< LLVOVolume* >::iterator iter = mObjectList.begin();
  3561. LLVOVolume* objp = *iter;
  3562. llassert_always(objp != NULL);
  3563. // The distance calculation is invalid for HUD attachments -- leave
  3564. // both mProximityDistance and mProximityCamera at 0 for them.
  3565. if (!objp->isHUDAttachment())
  3566. {
  3567. LLVector3d obj_global = objp->getPositionGlobal();
  3568. LLVector3d agent_global = gAgent.getPositionGlobal();
  3569. LLVector3d global_delta = agent_global - obj_global;
  3570. // use distance-squared because it's cheaper and sorts the same:
  3571. mProximityDistance = global_delta.lengthSquared();
  3572. LLVector3d camera_delta = gAgent.getCameraPositionGlobal() -
  3573. obj_global;
  3574. mProximityCamera = camera_delta.length();
  3575. }
  3576. }
  3577. if (mNeedsMuteCheck)
  3578. {
  3579. // Check all objects this instance is associated with, and those
  3580. // objects' owners, against the mute list
  3581. mIsMuted = false;
  3582. for (std::list<LLVOVolume*>::iterator iter = mObjectList.begin(),
  3583. end = mObjectList.end();
  3584. iter != end; ++iter)
  3585. {
  3586. LLVOVolume* obj = *iter;
  3587. if (!obj) continue;
  3588. if (LLMuteList::isMuted(obj->getID()))
  3589. {
  3590. mIsMuted = true;
  3591. }
  3592. else
  3593. {
  3594. // We may not have full permissions data for all objects.
  3595. // Attempt to mute objects when we can tell their owners are
  3596. // muted.
  3597. LLPermissions* obj_perm =
  3598. gSelectMgr.findObjectPermissions(obj);
  3599. if (obj_perm && LLMuteList::isMuted(obj_perm->getOwner()))
  3600. {
  3601. mIsMuted = true;
  3602. }
  3603. }
  3604. }
  3605. mNeedsMuteCheck = false;
  3606. }
  3607. }
  3608. F64 LLViewerMediaImpl::getApproximateTextureInterest()
  3609. {
  3610. F64 result = 0.0;
  3611. if (mMediaSource)
  3612. {
  3613. result = mMediaSource->getFullWidth();
  3614. result *= mMediaSource->getFullHeight();
  3615. }
  3616. else
  3617. {
  3618. // No media source is loaded -- all we have to go on is the texture
  3619. // size that has been set on the impl, if any.
  3620. result = mMediaWidth;
  3621. result *= mMediaHeight;
  3622. }
  3623. return result;
  3624. }
  3625. void LLViewerMediaImpl::setUsedInUI(bool used_in_ui)
  3626. {
  3627. mUsedInUI = used_in_ui;
  3628. // *HACK: Force elements used in UI to load right away. This fixes some
  3629. // issues where UI code that uses the browser instance does not expect it
  3630. // to be unloaded.
  3631. if (mUsedInUI && mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
  3632. {
  3633. if (getVisible())
  3634. {
  3635. setPriority(LLPluginClassMedia::PRIORITY_NORMAL);
  3636. }
  3637. else
  3638. {
  3639. setPriority(LLPluginClassMedia::PRIORITY_HIDDEN);
  3640. }
  3641. createMediaSource();
  3642. }
  3643. }
  3644. F64 LLViewerMediaImpl::getCPUUsage() const
  3645. {
  3646. return mMediaSource ? mMediaSource->getCPUUsage() : 0.0;
  3647. }
  3648. void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)
  3649. {
  3650. if (mPriority != priority)
  3651. {
  3652. LL_DEBUGS("PluginPriority") << "changing priority of media id "
  3653. << mTextureId << " from "
  3654. << LLPluginClassMedia::priorityToString(mPriority)
  3655. << " to "
  3656. << LLPluginClassMedia::priorityToString(priority)
  3657. << LL_ENDL;
  3658. mPriority = priority;
  3659. }
  3660. if (priority == LLPluginClassMedia::PRIORITY_UNLOADED)
  3661. {
  3662. if (mMediaSource)
  3663. {
  3664. // Need to unload the media source
  3665. // First, save off previous media state
  3666. mPreviousMediaState = mMediaSource->getStatus();
  3667. mPreviousMediaTime = mMediaSource->getCurrentTime();
  3668. destroyMediaSource();
  3669. }
  3670. }
  3671. if (mMediaSource)
  3672. {
  3673. mMediaSource->setPriority(mPriority);
  3674. }
  3675. // NOTE: loading (or reloading) media sources whose priority has risen
  3676. // above PRIORITY_UNLOADED is done in update().
  3677. }
  3678. void LLViewerMediaImpl::setLowPrioritySizeLimit(int size)
  3679. {
  3680. if (mMediaSource)
  3681. {
  3682. mMediaSource->setLowPrioritySizeLimit(size);
  3683. }
  3684. }
  3685. void LLViewerMediaImpl::setNavigateSuspended(bool suspend)
  3686. {
  3687. if (mNavigateSuspended != suspend)
  3688. {
  3689. mNavigateSuspended = suspend;
  3690. if (!suspend)
  3691. {
  3692. // We are coming out of suspend. If someone tried to do a navigate
  3693. // while suspended, do one now instead.
  3694. if (mNavigateSuspendedDeferred)
  3695. {
  3696. mNavigateSuspendedDeferred = false;
  3697. navigateInternal();
  3698. }
  3699. }
  3700. }
  3701. }
  3702. void LLViewerMediaImpl::cancelMimeTypeProbe()
  3703. {
  3704. LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter = mMimeProbe.lock();
  3705. if (adapter)
  3706. {
  3707. adapter->cancelSuspendedOperation();
  3708. }
  3709. }
  3710. void LLViewerMediaImpl::addObject(LLVOVolume* obj)
  3711. {
  3712. for (std::list<LLVOVolume*>::iterator iter = mObjectList.begin(),
  3713. end = mObjectList.end();
  3714. iter != end; ++iter)
  3715. {
  3716. if (*iter == obj)
  3717. {
  3718. return; // already in the list.
  3719. }
  3720. }
  3721. mObjectList.push_back(obj);
  3722. if (obj->isHUDAttachment())
  3723. {
  3724. mUsedOnHUD = true;
  3725. }
  3726. mNeedsMuteCheck = true;
  3727. }
  3728. void LLViewerMediaImpl::removeObject(LLVOVolume* obj)
  3729. {
  3730. mObjectList.remove(obj);
  3731. mNeedsMuteCheck = true;
  3732. if (mUsedOnHUD && !mObjectList.empty())
  3733. {
  3734. // Check to see if any remaining object using this impl is a HUD
  3735. mUsedOnHUD = false;
  3736. for (std::list<LLVOVolume*>::iterator iter = mObjectList.begin(),
  3737. end = mObjectList.end();
  3738. iter != end; ++iter)
  3739. {
  3740. LLVOVolume* obj = *iter;
  3741. if (obj && obj->isHUDAttachment())
  3742. {
  3743. mUsedOnHUD = true;
  3744. return; // No need to continue
  3745. }
  3746. }
  3747. }
  3748. }
  3749. const std::list<LLVOVolume*>* LLViewerMediaImpl::getObjectList() const
  3750. {
  3751. return &mObjectList;
  3752. }
  3753. LLVOVolume* LLViewerMediaImpl::getSomeObject()
  3754. {
  3755. LLVOVolume* result = NULL;
  3756. std::list<LLVOVolume*>::iterator iter = mObjectList.begin();
  3757. if (iter != mObjectList.end())
  3758. {
  3759. result = *iter;
  3760. }
  3761. return result;
  3762. }
  3763. void LLViewerMediaImpl::setTextureID(LLUUID id)
  3764. {
  3765. if (id != mTextureId)
  3766. {
  3767. if (mTextureId.notNull())
  3768. {
  3769. // Remove this item's entry from the map
  3770. sViewerMediaTextureIDMap.erase(mTextureId);
  3771. }
  3772. if (id.notNull())
  3773. {
  3774. sViewerMediaTextureIDMap[id] = this;
  3775. }
  3776. mTextureId = id;
  3777. }
  3778. }
  3779. bool LLViewerMediaImpl::isAutoPlayable() const
  3780. {
  3781. static LLCachedControl<bool> parcel_media_auto_play(gSavedSettings,
  3782. "ParcelMediaAutoPlayEnable");
  3783. static LLCachedControl<bool> tentative_auto_play(gSavedSettings,
  3784. "MediaTentativeAutoPlay");
  3785. return mMediaAutoPlay && tentative_auto_play &&
  3786. (parcel_media_auto_play || !isParcelMedia());
  3787. }
  3788. bool LLViewerMediaImpl::shouldShowBasedOnClass() const
  3789. {
  3790. static LLCachedControl<bool> show_media_on_others(gSavedSettings,
  3791. "MediaShowOnOthers");
  3792. static LLCachedControl<bool> show_media_within_parcel(gSavedSettings,
  3793. "MediaShowWithinParcel");
  3794. static LLCachedControl<bool> show_media_outside_parcel(gSavedSettings,
  3795. "MediaShowOutsideParcel");
  3796. // If this is parcel media, or in the UI, or on a HUD, return true always
  3797. if (getUsedInUI() || getUsedOnHUD() || isParcelMedia()) return true;
  3798. #if 0 // This is incorrect, and causes EXT-6750 (disabled attachment media
  3799. // still plays)
  3800. // If it has focus, we should show it
  3801. if (hasFocus()) return true;
  3802. #endif
  3803. if (isAttachedToAnotherAvatar())
  3804. {
  3805. return show_media_on_others;
  3806. }
  3807. if (isInAgentParcel())
  3808. {
  3809. return show_media_within_parcel;
  3810. }
  3811. else
  3812. {
  3813. return show_media_outside_parcel;
  3814. }
  3815. }
  3816. bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const
  3817. {
  3818. for (std::list<LLVOVolume*>::const_iterator iter = mObjectList.begin(),
  3819. end = mObjectList.end();
  3820. iter != end; ++iter)
  3821. {
  3822. LLVOVolume* obj = *iter;
  3823. if (obj)
  3824. {
  3825. LLVOAvatar* avatar = obj->getAvatarAncestor();
  3826. if (avatar && !avatar->isSelf())
  3827. {
  3828. return true;
  3829. }
  3830. }
  3831. }
  3832. return false;
  3833. }
  3834. bool LLViewerMediaImpl::isInAgentParcel() const
  3835. {
  3836. for (std::list<LLVOVolume*>::const_iterator iter = mObjectList.begin(),
  3837. end = mObjectList.end();
  3838. iter != end; ++iter)
  3839. {
  3840. LLVOVolume* obj = *iter;
  3841. if (obj && gViewerParcelMgr.inAgentParcel(obj->getPositionGlobal()))
  3842. {
  3843. return true;
  3844. }
  3845. }
  3846. return false;
  3847. }