From b543f291fcf945330fd5a533cc7235c20d7cb4c5 Mon Sep 17 00:00:00 2001 From: Armin Weatherwax Date: Sun, 13 Mar 2011 15:19:55 +0100 Subject: Henri Beauchamps version of Sione Lomus media filter patch. from http://sldev.free.fr/ : "MediaFilter_v3: based on code by Sione Lomu with a couple of bugfixes by Tonya Souther, this improved patch brings media and streaming audio URLs filtering (to prevent IP ripping by so-called security systems which violate the SL TOS by catching your IP and associating your various avatars with it, thus violating your anonimity). Beside empowering your viewer with allow/deny/blacklist/whitelist functions per domain, this improved patch makes the difference between external servers (domains names filtering) and in-world servers (scripted objects with built-in HTTP servers). I also fixed various bugs, security holes and shortcomings, refactored the code and improved it, and added a whitelist/blacklist erasing function." Imprudence changes: added "MediaFilter" debug to be able to inspect the full url and media texture uuid --- linden/indra/newview/CMakeLists.txt | 2 + linden/indra/newview/app_settings/logcontrol.xml | 1 + linden/indra/newview/app_settings/settings.xml | 27 ++ linden/indra/newview/lloverlaybar.cpp | 21 +- linden/indra/newview/lloverlaybar.h | 4 + linden/indra/newview/llstartup.cpp | 2 + linden/indra/newview/llviewercontrol.cpp | 3 +- linden/indra/newview/llviewermenu.cpp | 9 + linden/indra/newview/llviewerparcelmedia.cpp | 397 ++++++++++++++++++++- linden/indra/newview/llviewerparcelmedia.h | 24 +- linden/indra/newview/llviewerparcelmgr.cpp | 12 +- .../default/xui/en-us/floater_media_filter.xml | 61 ++++ .../skins/default/xui/en-us/menu_viewer.xml | 5 + .../skins/default/xui/en-us/notifications.xml | 50 +++ linden/indra/newview/slfloatermediafilter.cpp | 350 ++++++++++++++++++ linden/indra/newview/slfloatermediafilter.h | 70 ++++ 16 files changed, 1025 insertions(+), 13 deletions(-) create mode 100644 linden/indra/newview/skins/default/xui/en-us/floater_media_filter.xml create mode 100644 linden/indra/newview/slfloatermediafilter.cpp create mode 100644 linden/indra/newview/slfloatermediafilter.h diff --git a/linden/indra/newview/CMakeLists.txt b/linden/indra/newview/CMakeLists.txt index dedced0..9a4e2ed 100644 --- a/linden/indra/newview/CMakeLists.txt +++ b/linden/indra/newview/CMakeLists.txt @@ -498,6 +498,7 @@ set(viewer_SOURCE_FILES rlvmultistringsearch.cpp rlvextensions.cpp rlvfloaterbehaviour.cpp + slfloatermediafilter.cpp viewertime.cpp viewerversion.cpp windlightsettingsupdate.cpp @@ -967,6 +968,7 @@ set(viewer_HEADER_FILES rlvmultistringsearch.h rlvextensions.h rlvfloaterbehaviour.h + slfloatermediafilter.h VertexCache.h VorbisFramework.h viewertime.h diff --git a/linden/indra/newview/app_settings/logcontrol.xml b/linden/indra/newview/app_settings/logcontrol.xml index 51bb456..c9e9127 100644 --- a/linden/indra/newview/app_settings/logcontrol.xml +++ b/linden/indra/newview/app_settings/logcontrol.xml @@ -58,6 +58,7 @@ + MediaFilter diff --git a/linden/indra/newview/app_settings/settings.xml b/linden/indra/newview/app_settings/settings.xml index 59c2982..2a508ee 100644 --- a/linden/indra/newview/app_settings/settings.xml +++ b/linden/indra/newview/app_settings/settings.xml @@ -7990,6 +7990,33 @@ Value 3.0 + MediaEnableFilter + + Comment + Enable media domain filtering + Persist + 1 + Type + Boolean + Value + 1 + + MediaFilterRect + + Comment + Rectangle for Media Filter floater + Persist + 1 + Type + Rect + Value + + 0 + 100 + 100 + 100 + + MediaOnAPrimUI Comment diff --git a/linden/indra/newview/lloverlaybar.cpp b/linden/indra/newview/lloverlaybar.cpp index 4e1d03e..93b73c7 100644 --- a/linden/indra/newview/lloverlaybar.cpp +++ b/linden/indra/newview/lloverlaybar.cpp @@ -383,6 +383,23 @@ void LLOverlayBar::onClickStandUp(void*) } //////////////////////////////////////////////////////////////////////////////// +void LLOverlayBar::audioFilterPlay() +{ + if (gOverlayBar && gOverlayBar->mMusicState != PLAYING) + { + gOverlayBar->mMusicState = PLAYING; + } +} + +void LLOverlayBar::audioFilterStop() +{ + if (gOverlayBar && gOverlayBar->mMusicState != STOPPED) + { + gOverlayBar->mMusicState = STOPPED; + } +} + +//////////////////////////////////////////////////////////////////////////////// // static media helpers // *TODO: Move this into an audio manager abstraction //static @@ -416,6 +433,7 @@ void LLOverlayBar::toggleMediaPlay(void*) LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { + LLViewerParcelMedia::sIsUserAction = true; LLViewerParcelMedia::play(parcel); } } @@ -447,7 +465,8 @@ void LLOverlayBar::toggleMusicPlay(void*) // stream is stopped, it doesn't return the right thing - commenting out for now. // if ( gAudioStream->isInternetStreamPlaying() == 0 ) { - gAudioStream->startInternetStream(parcel->getMusicURL()); + LLViewerParcelMedia::sIsUserAction = true; + LLViewerParcelMedia::playStreamingMusic(parcel); } } } diff --git a/linden/indra/newview/lloverlaybar.h b/linden/indra/newview/lloverlaybar.h index 233f5c5..f776639 100644 --- a/linden/indra/newview/lloverlaybar.h +++ b/linden/indra/newview/lloverlaybar.h @@ -77,6 +77,10 @@ public: static void onClickStandUp(void* data); static void onClickResetView(void* data); + // media filter + static void audioFilterPlay(); + static void audioFilterStop(); + //static media helper functions static void toggleMediaPlay(void*); static void toggleMusicPlay(void*); diff --git a/linden/indra/newview/llstartup.cpp b/linden/indra/newview/llstartup.cpp index 5a3a8ee..a74744b 100644 --- a/linden/indra/newview/llstartup.cpp +++ b/linden/indra/newview/llstartup.cpp @@ -2822,6 +2822,8 @@ bool idle_startup() gFloaterTeleportHistory->addEntry(regionp->getName(),(S16)agent_pos.mV[0],(S16)agent_pos.mV[1],(S16)agent_pos.mV[2],false); } + LLViewerParcelMedia::loadDomainFilterList(); + // Let the map know about the inventory. if(gFloaterWorldMap) { diff --git a/linden/indra/newview/llviewercontrol.cpp b/linden/indra/newview/llviewercontrol.cpp index 572f64a..0a23045 100644 --- a/linden/indra/newview/llviewercontrol.cpp +++ b/linden/indra/newview/llviewercontrol.cpp @@ -63,6 +63,7 @@ #include "llworld.h" #include "pipeline.h" #include "llviewerjoystick.h" +#include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "llparcel.h" #include "llnotify.h" @@ -324,7 +325,7 @@ static bool handleAudioStreamMusicChanged(const LLSD& newvalue) // otherwise music will briefly stop if ( !gAudioStream->isInternetStreamPlaying() ) { - gAudioStream->startInternetStream(LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL()); + LLViewerParcelMedia::playStreamingMusic(LLViewerParcelMgr::getInstance()->getAgentParcel()); } } } diff --git a/linden/indra/newview/llviewermenu.cpp b/linden/indra/newview/llviewermenu.cpp index cf3cec1..a22f704 100644 --- a/linden/indra/newview/llviewermenu.cpp +++ b/linden/indra/newview/llviewermenu.cpp @@ -234,6 +234,7 @@ #include "hippolimits.h" #include "llfloaterteleporthistory.h" +#include "slfloatermediafilter.h" using namespace LLVOAvatarDefines; void init_client_menu(LLMenuGL* menu); @@ -5996,6 +5997,10 @@ class LLShowFloater : public view_listener_t { LLFloaterMute::toggleInstance(); } + else if (floater_name == "media filter") + { + SLFloaterMediaFilter::toggleInstance(); + } else if (floater_name == "camera controls") { LLFloaterCamera::toggleInstance(); @@ -6161,6 +6166,10 @@ class LLFloaterVisible : public view_listener_t { new_value = LLFloaterMute::instanceVisible(); } + else if (floater_name == "media filter") + { + new_value = SLFloaterMediaFilter::instanceVisible(); + } else if (floater_name == "camera controls") { new_value = LLFloaterCamera::instanceVisible(); diff --git a/linden/indra/newview/llviewerparcelmedia.cpp b/linden/indra/newview/llviewerparcelmedia.cpp index d4ebbd9..a5d97f2 100644 --- a/linden/indra/newview/llviewerparcelmedia.cpp +++ b/linden/indra/newview/llviewerparcelmedia.cpp @@ -33,6 +33,7 @@ #include "llviewerprecompiledheaders.h" #include "llviewerparcelmedia.h" +#include "kokuastreamingaudio.h" #include "llagent.h" #include "llviewercontrol.h" #include "llviewermedia.h" @@ -46,17 +47,27 @@ #include "llviewerwindow.h" #include "llfirstuse.h" #include "llpluginclassmedia.h" +#include "llnotify.h" +#include "llsdserialize.h" +#include "lloverlaybar.h" +#include "slfloatermediafilter.h" +#include "llinventorymodel.h" // Static Variables S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; LLUUID LLViewerParcelMedia::sMediaRegionID; viewer_media_t LLViewerParcelMedia::sMediaImpl; - +bool LLViewerParcelMedia::sIsUserAction = false; +bool LLViewerParcelMedia::sMediaFilterListLoaded = false; +LLSD LLViewerParcelMedia::sMediaFilterList; +std::set LLViewerParcelMedia::sMediaQueries; +std::set LLViewerParcelMedia::sAllowedMedia; +std::set LLViewerParcelMedia::sDeniedMedia; // Local functions bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); - +void callback_media_alert(const LLSD& notification, const LLSD& response, LLParcel* parcel, U32 type, std::string domain); // static void LLViewerParcelMedia::initClass() @@ -175,7 +186,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) } // static -void LLViewerParcelMedia::play(LLParcel* parcel) +void LLViewerParcelMedia::play(LLParcel* parcel, bool filter) { lldebugs << "LLViewerParcelMedia::play" << llendl; @@ -185,7 +196,17 @@ void LLViewerParcelMedia::play(LLParcel* parcel) return; std::string media_url = parcel->getMediaURL(); - std::string media_current_url = parcel->getMediaCurrentURL(); + LLStringUtil::trim(media_url); + + if (!media_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && (filter || !allowedMedia(media_url))) + { + // If filtering is needed or in case media_url just changed + // to something we did not yet approve. + LLViewerParcelMediaAutoPlay::playStarted(); + filterMedia(parcel, 0); + return; + } + std::string mime_type = parcel->getMediaType(); LLUUID placeholder_texture_id = parcel->getMediaID(); U8 media_auto_scale = parcel->getMediaAutoScale(); @@ -403,6 +424,8 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void * media_url = media_url_buffer; msg->getU8("DataBlock", "MediaAutoScale", media_auto_scale); + LL_DEBUGS("MediaFilter") << "New media texture id: " << media_id << LL_ENDL; + if (msg->has("DataBlockExtended")) // do we have the extended data? { char media_type_buffer[257]; @@ -438,6 +461,7 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void * play(parcel); } + } } // Static @@ -586,3 +610,368 @@ void LLViewerParcelMediaNavigationObserver::onNavigateComplete( const EventType& } */ + +void LLViewerParcelMedia::playStreamingMusic(LLParcel* parcel, bool filter) +{ + std::string music_url = parcel->getMusicURL(); + LLStringUtil::trim(music_url); + if (!music_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && (filter || !allowedMedia(music_url))) + { + // If filtering is needed or in case music_url just changed + // to something we did not yet approve. + filterMedia(parcel, 1); + } + else if (gAudioStream) + { + LLStringUtil::trim(music_url); + gAudioStream->startInternetStream(music_url); + if (music_url.empty()) + { + LLOverlayBar::audioFilterStop(); + } + else + { + LLOverlayBar::audioFilterPlay(); + } + } +} + +void LLViewerParcelMedia::stopStreamingMusic() +{ + if (gAudioStream) + { + gAudioStream->stopInternetStream(); + LLOverlayBar::audioFilterStop(); + } +} + +bool LLViewerParcelMedia::allowedMedia(std::string media_url) +{ + LLStringUtil::trim(media_url); + std::string domain = extractDomain(media_url); + if (sAllowedMedia.count(domain)) + { + return true; + } + for (S32 i = 0; i < (S32)sMediaFilterList.size(); i++) + { + if (sMediaFilterList[i]["domain"].asString() == domain) + { + if (sMediaFilterList[i]["action"].asString() == "allow") + { + return true; + } + else + { + return false; + } + } + } + return false; +} + +void LLViewerParcelMedia::filterMedia(LLParcel* parcel, U32 type) +{ + std::string media_action; + std::string media_url; + std::string domain; + + if (parcel != LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + // The parcel just changed (may occur right out after a TP) + sIsUserAction = false; + return; + } + + if (type == 0) + { + media_url = parcel->getMediaURL(); + } + else + { + media_url = parcel->getMusicURL(); + } + LLStringUtil::trim(media_url); + + LL_DEBUGS("MediaFilter") << "Requested " << (type == 0 ? "media" : "music") << "-URL: " << media_url << LL_ENDL; + + domain = extractDomain(media_url); + + if (sMediaQueries.count(domain) > 0) + { + sIsUserAction = false; + return; + } + + if (sIsUserAction) + { + // This was a user manual request to play this media, so give + // it another chance... + sIsUserAction = false; + if (sDeniedMedia.count(domain)) + { + sDeniedMedia.erase(domain); + SLFloaterMediaFilter::setDirty(); + } + } + + if (!sMediaFilterListLoaded || sDeniedMedia.count(domain)) + { + media_action = "ignore"; + } + else if (sAllowedMedia.count(domain)) + { + media_action = "allow"; + } + else + { + for (S32 i = 0; i < (S32)sMediaFilterList.size(); i++) + { + if (sMediaFilterList[i]["domain"].asString() == domain) + { + media_action = sMediaFilterList[i]["action"].asString(); + break; + } + } + } + + if (media_action == "allow" || media_url.empty()) + { + if (type == 0) + { + play(parcel, false); + } + else + { + playStreamingMusic(parcel, false); + } + } + else if (media_action == "deny") + { + LLSD args; + args["DOMAIN"] = domain; + LLNotifications::instance().add("MediaBlocked", args); + if (type == 1) + { + LLViewerParcelMedia::stopStreamingMusic(); + } + // So to avoid other "blocked" messages later in the session + // for this url should it be requested again by a script. + sDeniedMedia.insert(domain); + } + else if (media_action == "ignore") + { + if (type == 1) + { + LLViewerParcelMedia::stopStreamingMusic(); + } + } + else + { + sMediaQueries.insert(domain); + LLSD args; + args["DOMAIN"] = domain; + if (media_url.find('?') != std::string::npos) + { + args["WARNING"] = " (WARNING: this URL also contains parameter(s) that could potentially be used to correlate your avatar name with your IP)"; + } + else + { + args["WARNING"] = ""; + } + if (type == 0) + { + args["TYPE"] = "a media"; + } + else + { + args["TYPE"] = "an audio"; + } + LLNotifications::instance().add("MediaAlert", args, LLSD(), boost::bind(callback_media_alert, _1, _2, parcel, type, domain)); + } +} + +void callback_media_alert(const LLSD ¬ification, const LLSD &response, LLParcel* parcel, U32 type, std::string domain) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + + LLSD args; + args["DOMAIN"] = domain; + + if (option == 0 || option == 3) // Allow or Whitelist + { + LLViewerParcelMedia::sAllowedMedia.insert(domain); + if (option == 3) // Whitelist + { + LLSD newmedia; + newmedia["domain"] = domain; + newmedia["action"] = "allow"; + LLViewerParcelMedia::sMediaFilterList.append(newmedia); + LLViewerParcelMedia::saveDomainFilterList(); + args["LISTED"] = "whitelisted"; + LLNotifications::instance().add("MediaListed", args); + } + if (type == 0) + { + LLViewerParcelMedia::play(parcel, false); + } + else + { + LLViewerParcelMedia::playStreamingMusic(parcel, false); + } + } + else if (option == 1 || option == 2) // Deny or Blacklist + { + LLViewerParcelMedia::sDeniedMedia.insert(domain); + if (type == 1) + { + LLViewerParcelMedia::stopStreamingMusic(); + } + if (option == 1) // Deny + { + LLNotifications::instance().add("MediaBlocked", args); + } + else // Blacklist + { + LLSD newmedia; + newmedia["domain"] = domain; + newmedia["action"] = "deny"; + LLViewerParcelMedia::sMediaFilterList.append(newmedia); + LLViewerParcelMedia::saveDomainFilterList(); + args["LISTED"] = "blacklisted"; + LLNotifications::instance().add("MediaListed", args); + } + } + + LLViewerParcelMedia::sMediaQueries.erase(domain); + SLFloaterMediaFilter::setDirty(); +} + +void LLViewerParcelMedia::saveDomainFilterList() +{ + std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_filter.xml"); + + llofstream medialistFile(medialist_filename); + LLSDSerialize::toPrettyXML(sMediaFilterList, medialistFile); + medialistFile.close(); +} + +bool LLViewerParcelMedia::loadDomainFilterList() +{ + sMediaFilterListLoaded = true; + + std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_filter.xml"); + + if (!LLFile::isfile(medialist_filename)) + { + LLSD emptyllsd; + llofstream medialistFile(medialist_filename); + LLSDSerialize::toPrettyXML(emptyllsd, medialistFile); + medialistFile.close(); + } + + if (LLFile::isfile(medialist_filename)) + { + llifstream medialistFile(medialist_filename); + LLSDSerialize::fromXML(sMediaFilterList, medialistFile); + medialistFile.close(); + SLFloaterMediaFilter::setDirty(); + return true; + } + else + { + return false; + } +} + +void LLViewerParcelMedia::clearDomainFilterList() +{ + sMediaFilterList.clear(); + sAllowedMedia.clear(); + sDeniedMedia.clear(); + saveDomainFilterList(); + LLNotifications::instance().add("MediaFiltersCleared"); + SLFloaterMediaFilter::setDirty(); +} + +std::string LLViewerParcelMedia::extractDomain(std::string url) +{ + static std::string last_region = "@"; + + if (url.empty()) + { + return url; + } + + LLStringUtil::toLower(url); + + size_t pos = url.find("//"); + + if (pos != std::string::npos) + { + size_t count = url.size() - pos + 2; + url = url.substr(pos + 2, count); + } + + // Check that there is at least one slash in the URL and add a trailing + // one if not (for media/audio URLs such as http://mydomain.net) + if (url.find('/') == std::string::npos) + { + url += '/'; + } + + // If there's a user:password@ part, remove it + pos = url.find('@'); + if (pos != std::string::npos && pos < url.find('/')) // if '@' is not before the first '/', then it's not a user:password + { + size_t count = url.size() - pos + 1; + url = url.substr(pos + 1, count); + } + + if (url.find(gAgent.getRegion()->getHost().getHostName()) == 0 || url.find(last_region) == 0) + { + // This must be a scripted object rezzed in the region: + // extend the concept of "domain" to encompass the + // scripted object server id and avoid blocking all other + // objects at once in this region... + + // Get rid of any port number + pos = url.find('/'); // We earlier made sure that there's one + url = gAgent.getRegion()->getHost().getHostName() + url.substr(pos); + + pos = url.find('?'); + if (pos != std::string::npos) + { + // Get rid of any parameter + url = url.substr(0, pos); + } + + pos = url.rfind('/'); + if (pos != std::string::npos) + { + // Get rid of the filename, if any, keeping only the server + path + url = url.substr(0, pos); + } + } + else + { + pos = url.find(':'); + if (pos != std::string::npos && pos < url.find('/')) + { + // Keep anything before the port number and strip the rest off + url = url.substr(0, pos); + } + else + { + pos = url.find('/'); // We earlier made sure that there's one + url = url.substr(0, pos); + } + } + + + // Remember this region, so to cope with requests occuring just after a + // TP out of it. + last_region = gAgent.getRegion()->getHost().getHostName(); + + return url; +} diff --git a/linden/indra/newview/llviewerparcelmedia.h b/linden/indra/newview/llviewerparcelmedia.h index 0f1e85c..7531a0f 100644 --- a/linden/indra/newview/llviewerparcelmedia.h +++ b/linden/indra/newview/llviewerparcelmedia.h @@ -35,6 +35,9 @@ #include "llviewermedia.h" +// For use by other patches so they know that media filtering is implemented. +#define MEDIA_FILTERING 1 + class LLMessageSystem; class LLParcel; class LLViewerParcelMediaNavigationObserver; @@ -54,8 +57,20 @@ class LLViewerParcelMedia : public LLViewerMediaObserver // called when the agent's parcel has a new URL, or the agent has // walked on to a new parcel with media - static void play(LLParcel* parcel); + static void play(LLParcel* parcel, bool filter = true); // user clicked play button in media transport controls + static void playStreamingMusic(LLParcel* parcel, bool filter = true); + // play the parcel music stream + static void stopStreamingMusic(); + // stop the parcel music stream + + static void filterMedia(LLParcel* parcel, U32 type); // type: 0 = media, 1 = streaming music + static bool allowedMedia(std::string media_url); + + static bool loadDomainFilterList(); + static void saveDomainFilterList(); + static void clearDomainFilterList(); + static std::string extractDomain(std::string url); static void stop(); // user clicked stop button in media transport controls @@ -85,6 +100,13 @@ class LLViewerParcelMedia : public LLViewerMediaObserver static LLUUID sMediaRegionID; // HACK: this will change with Media on a Prim static viewer_media_t sMediaImpl; + + static bool sIsUserAction; + static bool sMediaFilterListLoaded; + static LLSD sMediaFilterList; + static std::set sMediaQueries; + static std::set sAllowedMedia; + static std::set sDeniedMedia; }; diff --git a/linden/indra/newview/llviewerparcelmgr.cpp b/linden/indra/newview/llviewerparcelmgr.cpp index 630da54..9db65c6 100644 --- a/linden/indra/newview/llviewerparcelmgr.cpp +++ b/linden/indra/newview/llviewerparcelmgr.cpp @@ -85,7 +85,7 @@ LLPointer sBlockedImage; LLPointer sPassImage; // Local functions -void optionally_start_music(const std::string& music_url); +void optionally_start_music(LLParcel* parcel); void callback_start_music(S32 option, void* data); void optionally_prepare_video(const LLParcel *parcelp); void callback_prepare_video(S32 option, void* data); @@ -1697,7 +1697,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use { if (music_url.substr(0,7) == "http://") { - optionally_start_music(music_url); + optionally_start_music(parcel); } } else if (!gAudioStream->getInternetStreamURL().empty()) @@ -1719,18 +1719,18 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use }; } -void optionally_start_music(const std::string& music_url) +void optionally_start_music(LLParcel* parcel) { if (gSavedSettings.getBOOL("AudioStreamingMusic")) { // Make the user click the start button on the overlay bar. JC - // llinfos << "Starting parcel music " << music_url << llendl; + // llinfos << "Starting parcel music " << parcel->getMusicURL() << llendl; // now only play music when you enter a new parcel if the control is in PLAY state // changed as part of SL-4878 - if ( gOverlayBar && gOverlayBar->musicPlaying()) + if (gOverlayBar && gOverlayBar->musicPlaying()) { - gAudioStream->startInternetStream(music_url); + LLViewerParcelMedia::playStreamingMusic(parcel); } } } diff --git a/linden/indra/newview/skins/default/xui/en-us/floater_media_filter.xml b/linden/indra/newview/skins/default/xui/en-us/floater_media_filter.xml new file mode 100644 index 0000000..9b7355c --- /dev/null +++ b/linden/indra/newview/skins/default/xui/en-us/floater_media_filter.xml @@ -0,0 +1,61 @@ + + + + Domains in bold are in the persistent list (i.e. they are whitelisted or blacklisted). + + + Domains in italics are in the session list (i.e. they are temporarily allowed or denied). + + + + + + + + + + +