/** * @file llviewerparcelmedia.cpp * @brief Handlers for multimedia on a per-parcel basis * * $LicenseInfo:firstyear=2007&license=viewergpl$ * * Copyright (c) 2007-2008, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlife.com/developers/opensource/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at http://secondlife.com/developers/opensource/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llviewerparcelmedia.h" #include "llagent.h" #include "llviewercontrol.h" #include "llviewermedia.h" #include "llviewerregion.h" #include "llparcel.h" #include "llviewerparcelmgr.h" #include "lluuid.h" #include "message.h" #include "llviewerparcelmediaautoplay.h" #include "llviewerwindow.h" #include "llfirstuse.h" // Static Variables S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; LLUUID LLViewerParcelMedia::sMediaRegionID; // Local functions void callback_play_media(S32 option, void* data); // Move this to its own file. // helper class that tries to download a URL from a web site and calls a method // on the Panel Land Media and to discover the MIME type class LLMimeDiscoveryResponder : public LLHTTPClient::Responder { public: LLMimeDiscoveryResponder( ) {} virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) { std::string media_type = content["content-type"].asString(); std::string::size_type idx1 = media_type.find_first_of(";"); std::string mime_type = media_type.substr(0, idx1); completeAny(status, mime_type); } virtual void error( U32 status, const std::string& reason ) { completeAny(status, "none/none"); } void completeAny(U32 status, const std::string& mime_type) { LLViewerMedia::setMimeType(mime_type); } }; // static void LLViewerParcelMedia::initClass() { LLMessageSystem* msg = gMessageSystem; msg->setHandlerFunc("ParcelMediaCommandMessage", processParcelMediaCommandMessage ); msg->setHandlerFunc("ParcelMediaUpdate", processParcelMediaUpdate ); LLViewerParcelMediaAutoPlay::initClass(); } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::update(LLParcel* parcel) { if (/*LLViewerMedia::hasMedia()*/ true) { // we have a player if (parcel) { if(!gAgent.getRegion()) { sMediaRegionID = LLUUID() ; stop() ; return ; } // we're in a parcel bool new_parcel = false; S32 parcelid = parcel->getLocalID(); LLUUID regionid = gAgent.getRegion()->getRegionID(); if (parcelid != sMediaParcelLocalID || regionid != sMediaRegionID) { sMediaParcelLocalID = parcelid; sMediaRegionID = regionid; new_parcel = true; } std::string mediaUrl = std::string ( parcel->getMediaURL () ); LLStringUtil::trim(mediaUrl); // has something changed? if ( ( LLViewerMedia::getMediaURL() != mediaUrl ) || ( LLViewerMedia::getMediaTextureID() != parcel->getMediaID () ) ) { bool video_was_playing = FALSE; bool same_media_id = LLViewerMedia::getMediaTextureID() == parcel->getMediaID (); if (LLViewerMedia::isMediaPlaying()) { video_was_playing = TRUE; } if ( !mediaUrl.empty() && same_media_id && ! new_parcel) { // Someone has "changed the channel", changing the URL of a video // you were already watching. Automatically play provided the texture ID is the same if (video_was_playing) { // Poke the mime type in before calling play. // This is necessary because in this instance we are not waiting // for the results of a header curl. In order to change the channel // a mime type MUST be provided. LLViewerMedia::setMimeType(parcel->getMediaType()); play(parcel); } } else { stop(); } // Discover the MIME type // Disabled for the time being. Get the mime type from the parcel. if(gSavedSettings.getBOOL("AutoMimeDiscovery")) { LLHTTPClient::getHeaderOnly( mediaUrl, new LLMimeDiscoveryResponder()); } else { LLViewerMedia::setMimeType(parcel->getMediaType()); } // First use warning if( gSavedSettings.getWarning("FirstStreamingVideo") ) { gViewerWindow->alertXml("ParcelCanPlayMedia", callback_play_media, (void*)parcel); } } } else { stop(); } } /* else { // no audio player, do a first use dialog if their is media here if (parcel) { std::string mediaUrl = std::string ( parcel->getMediaURL () ); if (!mediaUrl.empty ()) { if (gSavedSettings.getWarning("QuickTimeInstalled")) { gSavedSettings.setWarning("QuickTimeInstalled", FALSE); LLNotifyBox::showXml("NoQuickTime" ); }; } } } */ } // static void LLViewerParcelMedia::play(LLParcel* parcel) { lldebugs << "LLViewerParcelMedia::play" << llendl; if (!parcel) return; if (!gSavedSettings.getBOOL("AudioStreamingVideo")) return; std::string media_url = parcel->getMediaURL(); std::string mime_type = parcel->getMediaType(); LLUUID placeholder_texture_id = parcel->getMediaID(); U8 media_auto_scale = parcel->getMediaAutoScale(); U8 media_loop = parcel->getMediaLoop(); S32 media_width = parcel->getMediaWidth(); S32 media_height = parcel->getMediaHeight(); LLViewerMedia::play(media_url, mime_type, placeholder_texture_id, media_width, media_height, media_auto_scale, media_loop); LLFirstUse::useMedia(); LLViewerParcelMediaAutoPlay::playStarted(); } // static void LLViewerParcelMedia::stop() { LLViewerMedia::stop(); } // static void LLViewerParcelMedia::pause() { LLViewerMedia::pause(); } // static void LLViewerParcelMedia::start() { LLViewerMedia::start(); LLFirstUse::useMedia(); LLViewerParcelMediaAutoPlay::playStarted(); } // static void LLViewerParcelMedia::seek(F32 time) { LLViewerMedia::seek(time); } // static LLMediaBase::EStatus LLViewerParcelMedia::getStatus() { return LLViewerMedia::getStatus(); } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg, void ** ) { // extract the agent id // LLUUID agent_id; // msg->getUUID( agent_id ); U32 flags; U32 command; F32 time; msg->getU32( "CommandBlock", "Flags", flags ); msg->getU32( "CommandBlock", "Command", command); msg->getF32( "CommandBlock", "Time", time ); if (flags &( (1<getAgentParcel(); play(parcel); } } else // unload if( command == PARCEL_MEDIA_COMMAND_UNLOAD ) { stop(); } } if (flags & (1<getAgentParcel(); play(parcel); } seek(time); } } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void ** ) { LLUUID media_id; std::string media_url; std::string media_type; S32 media_width = 0; S32 media_height = 0; U8 media_auto_scale = FALSE; U8 media_loop = FALSE; msg->getUUID( "DataBlock", "MediaID", media_id ); char media_url_buffer[257]; msg->getString( "DataBlock", "MediaURL", 255, media_url_buffer ); media_url = media_url_buffer; msg->getU8("DataBlock", "MediaAutoScale", media_auto_scale); if (msg->has("DataBlockExtended")) // do we have the extended data? { char media_type_buffer[257]; msg->getString("DataBlockExtended", "MediaType", 255, media_type_buffer); media_type = media_type_buffer; msg->getU8("DataBlockExtended", "MediaLoop", media_loop); msg->getS32("DataBlockExtended", "MediaWidth", media_width); msg->getS32("DataBlockExtended", "MediaHeight", media_height); } LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); BOOL same = FALSE; if (parcel) { same = ((parcel->getMediaURL() == media_url) && (parcel->getMediaType() == media_type) && (parcel->getMediaID() == media_id) && (parcel->getMediaWidth() == media_width) && (parcel->getMediaHeight() == media_height) && (parcel->getMediaAutoScale() == media_auto_scale) && (parcel->getMediaLoop() == media_loop)); if (!same) { // temporarily store these new values in the parcel parcel->setMediaURL(media_url); parcel->setMediaType(media_type); parcel->setMediaID(media_id); parcel->setMediaWidth(media_width); parcel->setMediaHeight(media_height); parcel->setMediaAutoScale(media_auto_scale); parcel->setMediaLoop(media_loop); play(parcel); } } } void callback_play_media(S32 option, void* data) { LLParcel* parcel = (LLParcel*)data; if (option == 0) { gSavedSettings.setBOOL("AudioStreamingVideo", TRUE); LLViewerParcelMedia::play(parcel); } else { gSavedSettings.setBOOL("AudioStreamingVideo", FALSE); } gSavedSettings.setWarning("FirstStreamingVideo", FALSE); }