From c06db583a2ef7d1aa31ec8cc6613fa7a1af38018 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Thu, 11 Nov 2010 22:00:01 +0100 Subject: [PATCH] Henry's Media Fixes --- indra/llplugin/llpluginmessagepipe.cpp | 8 +- indra/llplugin/llpluginprocesschild.cpp | 18 ++- indra/llplugin/llpluginprocessparent.cpp | 2 +- indra/llplugin/slplugin/slplugin.cpp | 13 +- .../quicktime/media_plugin_quicktime.cpp | 4 +- .../webkit/media_plugin_webkit.cpp | 139 +++++++++++++----- indra/newview/llviewermedia.cpp | 29 +++- indra/newview/llviewerparcelmedia.cpp | 49 +++--- .../default/xui/en-us/mime_types_linux.xml | 37 ++++- .../default/xui/en-us/mime_types_mac.xml | 35 ++++- .../default/xui/en-us/mime_types_windows.xml | 37 ++++- 11 files changed, 287 insertions(+), 84 deletions(-) diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index 209f49fe8..ac8872938 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -303,8 +303,14 @@ void LLPluginMessagePipe::processInput(void) while((delim = mInput.find(MESSAGE_DELIMITER, start)) != std::string::npos) { // Let the owner process this message + if (mOwner) + { mOwner->receiveMessageRaw(mInput.substr(start, delim - start)); - + } + else + { + LL_WARNS("Plugin") << "!mOwner" << LL_ENDL; + } start = delim + 1; } diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index 9b5eafce9..80404e379 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -53,8 +53,14 @@ LLPluginProcessChild::~LLPluginProcessChild() if(mInstance != NULL) { sendMessageToPlugin(LLPluginMessage("base", "cleanup")); - delete mInstance; - mInstance = NULL; + + // IMPORTANT: under some (unknown) circumstances the apr_dso_unload() triggered when mInstance is deleted + // appears to fail and lock up which means that a given instance of the slplugin process never exits. + // This is bad, especially when users try to update their version of SL - it fails because the slplugin + // process as well as a bunch of plugin specific files are locked and cannot be overwritten. + exit(0); + //delete mInstance; + //mInstance = NULL; } } @@ -270,6 +276,8 @@ bool LLPluginProcessChild::isDone(void) void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) { + if (mInstance) + { std::string buffer = message.generate(); LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL; @@ -278,6 +286,11 @@ void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) mInstance->sendMessage(buffer); mCPUElapsed += elapsed.getElapsedTimeF64(); + } + else + { + LL_WARNS("Plugin") << "mInstance == NULL" << LL_ENDL; + } } void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message) @@ -352,6 +365,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message) else { LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; + delete region; } } diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index bd36d11e8..526ba654e 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -53,7 +53,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner) mDebug = false; mPluginLaunchTimeout = 60.0f; - mPluginLockupTimeout = 30.0f; + mPluginLockupTimeout = 15.0f; // Don't start the timer here -- start it when we actually launch the plugin process. mHeartbeat.stop(); diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index fa3924b6f..b866c94a1 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -203,6 +203,8 @@ int main(int argc, char **argv) // see the missing heartbeat and log appropriately. initExceptionHandler(); #elif LL_DARWIN || LL_LINUX + setpriority(PRIO_PROCESS, getpid(), 19); + if(argc < 2) { LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL; @@ -236,6 +238,9 @@ int main(int argc, char **argv) checkExceptionHandler(); #endif +#if LL_DARWIN + EventTargetRef event_target = GetEventDispatcherTarget(); +#endif while(!plugin->isDone()) { timer.reset(); @@ -243,8 +248,12 @@ int main(int argc, char **argv) #if LL_DARWIN { // Some plugins (webkit at least) will want an event loop. This qualifies. - EventRecord evt; - WaitNextEvent(0, &evt, 0, NULL); + EventRef event; + if(ReceiveNextEvent(0, 0, kEventDurationNoWait, true, &event) == noErr) + { + SendEventToEventTarget (event, event_target); + ReleaseEvent(event); + } } #endif F64 elapsed = timer.getElapsedTimeF64(); diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index 6c8c41dbb..573ac863b 100644 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -721,8 +721,8 @@ private: return false; // allocate some space and grab it - UInt8* item_data = new UInt8( size + 1 ); - memset( item_data, 0, ( size + 1 ) * sizeof( UInt8* ) ); + UInt8* item_data = new UInt8[size + 1]; + memset(item_data, 0, (size + 1) * sizeof(UInt8)); result = QTMetaDataGetItemValue( media_data_ref, item, item_data, size, NULL ); if ( noErr != result ) { diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 91efdaecb..9a576ee6e 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -49,6 +49,13 @@ #include #endif +#if LL_LINUX +extern "C" { +#include +#include +} +#endif // LL_LINUX + #if LL_WINDOWS // NOTE - This captures the module handle of the dll. This is used below // to get the path to this dll for webkit initialization. @@ -80,9 +87,11 @@ private: enum { INIT_STATE_UNINITIALIZED, // Browser instance hasn't been set up yet + INIT_STATE_INITIALIZED, // LLQtWebkit has been set up, but no browser window has been created yet. INIT_STATE_NAVIGATING, // Browser instance has been set up and initial navigate to about:blank has been issued INIT_STATE_NAVIGATE_COMPLETE, // initial navigate to about:blank has completed INIT_STATE_WAIT_REDRAW, // First real navigate begin has been received, waiting for page changed event to start handling redraws + INIT_STATE_WAIT_COMPLETE, // Waiting for first real navigate complete event INIT_STATE_RUNNING // All initialization gymnastics are complete. }; int mBrowserWindowId; @@ -107,6 +116,16 @@ private: // void update(int milliseconds) { +#if LL_QTLINUX_DOESNT_HAVE_GLIB + // pump glib generously, as Linux browser plugins are on the + // glib main loop, even if the browser itself isn't - ugh + // This is NOT NEEDED if Qt itself was built with glib + // mainloop integration. + GMainContext *mainc = g_main_context_default(); + while(g_main_context_iteration(mainc, FALSE)); +#endif // LL_QTLINUX_DOESNT_HAVE_GLIB + + // pump qt LLQtWebKit::getInstance()->pump( milliseconds ); checkEditState(); @@ -121,7 +140,7 @@ private: } } - if ( (mInitState == INIT_STATE_RUNNING) && mNeedsUpdate ) + if (mInitState > INIT_STATE_WAIT_REDRAW && mNeedsUpdate) { const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); @@ -154,13 +173,6 @@ private: if ( mInitState > INIT_STATE_UNINITIALIZED ) return true; - // not enough information to initialize the browser yet. - if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || - mTextureWidth < 0 || mTextureHeight < 0 ) - { - return false; - }; - // set up directories char cwd[ FILENAME_MAX ]; // I *think* this is defined on all platforms we use if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) @@ -170,6 +182,23 @@ private: } std::string application_dir = std::string( cwd ); +#if LL_LINUX + // take care to initialize glib properly, because some + // versions of Qt don't, and we indirectly need it for (some + // versions of) Flash to not crash the browser. + if (!g_thread_supported ()) g_thread_init (NULL); + g_type_init(); +#endif // LL_LINUX + +#if LL_DARWIN + // When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on. + // This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger. + // This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it + // which gets hit when the plugin is probed by webkit. + // Unsetting the environment variable here works around this issue. + unsetenv("USERBREAK"); +#endif + #if LL_WINDOWS // NOTE - On windows, at least, the component path is the // location of this dll's image file. @@ -208,36 +237,52 @@ private: bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); if ( result ) { - // create single browser window - mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight ); + mInitState = INIT_STATE_INITIALIZED; -#if LL_WINDOWS - // Enable plugins + return true; + }; + + return false; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + bool initBrowserWindow() + { + // already initialized + if (mInitState > INIT_STATE_INITIALIZED) + return true; + + // not enough information to initialize the browser yet. + if (mWidth < 0 || mHeight < 0 || mDepth < 0 || + mTextureWidth < 0 || mTextureHeight < 0) + { + return false; + }; + + // turn on/off cookies based on what host app tells us + LLQtWebKit::getInstance()->enableCookies(true); + + // turn on/off plugins based on what host app tells us LLQtWebKit::getInstance()->enablePlugins(true); -#elif LL_DARWIN - // Enable plugins - LLQtWebKit::getInstance()->enablePlugins(true); -#elif LL_LINUX - // Enable plugins - LLQtWebKit::getInstance()->enablePlugins(true); -#endif - // Enable cookies - LLQtWebKit::getInstance()->enableCookies( true ); + + // create single browser window + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow(mWidth, mHeight); // tell LLQtWebKit about the size of the browser window - LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + LLQtWebKit::getInstance()->setSize(mBrowserWindowId, mWidth, mHeight); // observer events that LLQtWebKit emits - LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); + LLQtWebKit::getInstance()->addObserver(mBrowserWindowId, this); // append details to agent string - LLQtWebKit::getInstance()->setBrowserAgentId( "LLPluginMedia Web Browser" ); + LLQtWebKit::getInstance()->setBrowserAgentId("LLPluginMedia Web Browser"); // don't flip bitmap - LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); + LLQtWebKit::getInstance()->flipWindow(mBrowserWindowId, true); // set background color to be black - mostly for initial login page - LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 ); + LLQtWebKit::getInstance()->setBackgroundColor(mBrowserWindowId, 0x00, 0x00, 0x00); // Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. setInitState(INIT_STATE_NAVIGATING); @@ -245,14 +290,11 @@ private: // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. // FIXME: Re-added this because navigating to a "page" initializes things correctly - especially // for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date. - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); + LLQtWebKit::getInstance()->navigateTo(mBrowserWindowId, "about:blank"); return true; }; - return false; - }; - //////////////////////////////////////////////////////////////////////////////// // virtual void onCursorChanged(const EventType& event) @@ -294,7 +336,7 @@ private: { if(mInitState == INIT_STATE_WAIT_REDRAW) { - setInitState(INIT_STATE_RUNNING); + setInitState(INIT_STATE_WAIT_COMPLETE); } // flag that an update is required @@ -316,7 +358,9 @@ private: if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) { - setInitState(INIT_STATE_WAIT_REDRAW); + // Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary. +// setInitState(INIT_STATE_WAIT_REDRAW); + setInitState(INIT_STATE_WAIT_COMPLETE); } } @@ -327,6 +371,14 @@ private: { if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) { + if (mInitState < INIT_STATE_RUNNING) + { + setInitState(INIT_STATE_RUNNING); + + // Clear the history, so the "back" button doesn't take you back to "about:blank". + LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); + } + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); message.setValue("uri", event.getEventUri()); message.setValueS32("result_code", event.getIntValue()); @@ -594,6 +646,9 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) { if(message_name == "init") { + // This is the media init message -- all necessary data for initialization should have been received. + if (initBrowser()) + { std::string user_data_path = message_in.getValue("user_data_path"); // n.b. always has trailing platform-specific dir-delimiter mProfileDir = user_data_path + "browser_profile"; @@ -621,6 +676,12 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) message.setValueU32("type", GL_UNSIGNED_BYTE); message.setValueBoolean("coords_opengl", true); sendMessage(message); + } + else + { + // if initialization failed, we're done. + mDeleteMe = true; + } } else if(message_name == "idle") { @@ -706,9 +767,8 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) mWidth = width; mHeight = height; - // initialize (only gets called once) - initBrowser(); - + if (initBrowserWindow()) + { // size changed so tell the browser LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); @@ -718,7 +778,7 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); // The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response. - if(real_width <= texture_width) + if (real_width <= texture_width) { texture_width = real_width; } @@ -729,10 +789,15 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) mDeleteMe = true; return; } + } + else + { + // Setting up the browser window failed. This is a fatal error. + mDeleteMe = true; + } mTextureWidth = texture_width; mTextureHeight = texture_height; - }; }; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 74d38c206..c257e38f8 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -247,8 +247,7 @@ std::string LLViewerMedia::getCurrentUserAgent() // Just in case we need to check browser differences in A/B test // builds. - - std::string channel = LL_CHANNEL; + std::string channel = gSavedSettings.getString("VersionChannelName"); // append our magic version number string to the browser user agent id // See the HTTP 1.0 and 1.1 specifications for allowed formats: @@ -463,6 +462,19 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ std::string user_data_path = gDirUtilp->getOSUserAppDir(); user_data_path += gDirUtilp->getDirDelimiter(); + // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.) + // If the linden username returned is blank, that can only mean we are + // at the login page displaying login Web page or Web browser test via Develop menu. + // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this + // is what we always used before this change) + std::string linden_user_dir = gDirUtilp->getLindenUserDir(); + if (!linden_user_dir.empty()) + { + // gDirUtilp->getLindenUserDir() is whole path, not just Linden name + user_data_path = linden_user_dir; + user_data_path += gDirUtilp->getDirDelimiter(); + } + // See if the plugin executable exists llstat s; if(LLFile::stat(launcher_name, &s)) @@ -703,8 +715,12 @@ void LLViewerMediaImpl::navigateHome() } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type) +void LLViewerMediaImpl::navigateTo(const std::string& _url, const std::string& mime_type, bool rediscover_type) { + // trim whitespace from front and back of URL - fixes EXT-5363 + std::string url(_url); + LLStringUtil::trim(url); + if(rediscover_type) { @@ -713,7 +729,12 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi if(scheme.empty() || "http" == scheme || "https" == scheme) { - LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this)); + // If we don't set an Accept header, LLHTTPClient will add one like this: + // Accept: application/llsd+xml + // which is really not what we want. + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + LLHTTPClient::getHeaderOnly(url, new LLMimeDiscoveryResponder(this), headers, 10.0f); } else if("data" == scheme || "file" == scheme || "about" == scheme) { diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index d4ebbd93e..2b6ba910f 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -196,45 +196,34 @@ void LLViewerParcelMedia::play(LLParcel* parcel) // Debug print // LL_DEBUGS("Media") << "Play media type : " << mime_type << ", url : " << media_url << LL_ENDL; - if(sMediaImpl) + if (!sMediaImpl || (sMediaImpl && + (sMediaImpl->getMediaURL() != media_url || + sMediaImpl->getMimeType() != mime_type || + sMediaImpl->getMediaTextureID() != placeholder_texture_id))) { - // If the url and mime type are the same, call play again - if(sMediaImpl->getMediaURL() == media_url - && sMediaImpl->getMimeType() == mime_type - && sMediaImpl->getMediaTextureID() == placeholder_texture_id) + if (sMediaImpl) { - LL_DEBUGS("Media") << "playing with existing url " << media_url << LL_ENDL; - - sMediaImpl->play(); - } - // Else if the texture id's are the same, navigate and rediscover type - // MBW -- This causes other state from the previous parcel (texture size, autoscale, and looping) to get re-used incorrectly. - // It's also not really necessary -- just creating a new instance is fine. -// else if(sMediaImpl->getMediaTextureID() == placeholder_texture_id) -// { -// sMediaImpl->navigateTo(media_url, mime_type, true); -// } - else - { - // Since the texture id is different, we need to generate a new impl - LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; - - // Delete the old one first so they don't fight over the texture. + // Delete the old media impl first so they don't fight over the texture. sMediaImpl->stop(); + } + LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; + + // There is no media impl, or it has just been deprecated, make a new one sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, media_width, media_height, media_auto_scale, media_loop, mime_type); } - } - else - { - // There is no media impl, make a new one - sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, - media_width, media_height, media_auto_scale, - media_loop, mime_type); - } + // The url, mime type and texture are now the same, call play again + if (sMediaImpl->getMediaURL() == media_url + && sMediaImpl->getMimeType() == mime_type + && sMediaImpl->getMediaTextureID() == placeholder_texture_id) + { + LL_DEBUGS("Media") << "playing with existing url " << media_url << LL_ENDL; + + sMediaImpl->play(); + } LLFirstUse::useMedia(); diff --git a/indra/newview/skins/default/xui/en-us/mime_types_linux.xml b/indra/newview/skins/default/xui/en-us/mime_types_linux.xml index 2977d7a2e..f04992ade 100644 --- a/indra/newview/skins/default/xui/en-us/mime_types_linux.xml +++ b/indra/newview/skins/default/xui/en-us/mime_types_linux.xml @@ -120,7 +120,7 @@ none - media_plugin_gstreamer + media_plugin_webkit @@ -130,6 +130,9 @@ none + + media_plugin_webkit + @@ -224,6 +251,9 @@ web + + media_plugin_webkit + @@ -224,6 +251,9 @@ web + + media_plugin_webkit + @@ -130,6 +130,9 @@ none + + media_plugin_webkit + @@ -224,6 +251,9 @@ web + + media_plugin_webkit +