diff --git a/dom/plugins/base/npapi.h b/dom/plugins/base/npapi.h index 35146a1b9ff..2c773b096b3 100644 --- a/dom/plugins/base/npapi.h +++ b/dom/plugins/base/npapi.h @@ -411,7 +411,9 @@ typedef enum { , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */ , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated Cocoa text input specification. */ +#endif , NPNVmuteAudioBool = 4000 /* Request that the browser wants to mute or unmute the plugin */ +#if defined(XP_MACOSX) , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports CA model compositing */ #endif diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index 7c2f622c1c8..d677d92fce9 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -106,6 +106,8 @@ using mozilla::plugins::PluginModuleContentParent; #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #endif +#include "nsIAudioChannelAgent.h" + using namespace mozilla; using namespace mozilla::plugins::parent; @@ -2403,23 +2405,42 @@ _setvalue(NPP npp, NPPVariable variable, void *result) } case NPPVpluginIsPlayingAudio: { - // For testing, remove me - printf("set audio %p\n", result); - bool isPlaying = !!result; + bool isMuted = !result; - nsCOMPtr doc = GetDocumentFromNPP(npp); - if (doc) { - nsCOMPtr domwindow = doc->GetWindow(); - nsCOMPtr observerService = - services::GetObserverService(); - if (observerService) { - // XXX THIS NEEDS A BETTER API - observerService->NotifyObservers(ToSupports(domwindow), - "media-playback", - isPlaying ? NS_LITERAL_STRING("active").get() : - NS_LITERAL_STRING("inactive").get()); + nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*) npp->ndata; + MOZ_ASSERT(inst); + + if (isMuted && !inst->HasAudioChannelAgent()) { + return NPERR_NO_ERROR; + } + + nsCOMPtr agent; + nsresult rv = inst->GetOrCreateAudioChannelAgent(getter_AddRefs(agent)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; + } + + MOZ_ASSERT(agent); + + if (isMuted) { + rv = agent->NotifyStoppedPlaying(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; + } + } else { + float volume = 0.0; + bool muted = true; + rv = agent->NotifyStartedPlaying(&volume, &muted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; + } + + rv = inst->WindowVolumeChanged(volume, muted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; } } + return NPERR_NO_ERROR; } diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 4f35b147ab7..a15a9f20926 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -40,6 +40,7 @@ #include "mozilla/unused.h" #include "nsILoadContext.h" #include "mozilla/dom/HTMLObjectElementBinding.h" +#include "AudioChannelService.h" using namespace mozilla; using namespace mozilla::dom; @@ -169,7 +170,7 @@ using namespace mozilla::layers; static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); -NS_IMPL_ISUPPORTS0(nsNPAPIPluginInstance) +NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback) nsNPAPIPluginInstance::nsNPAPIPluginInstance() : mDrawingModel(kDefaultDrawingModel) @@ -253,6 +254,7 @@ nsNPAPIPluginInstance::Destroy() { Stop(); mPlugin = nullptr; + mAudioChannelAgent = nullptr; #if MOZ_WIDGET_ANDROID if (mContentSurface) @@ -1788,3 +1790,71 @@ nsNPAPIPluginInstance::GetRunID(uint32_t* aRunID) return library->GetRunID(aRunID); } + +nsresult +nsNPAPIPluginInstance::GetOrCreateAudioChannelAgent(nsIAudioChannelAgent** aAgent) +{ + if (!mAudioChannelAgent) { + nsresult rv; + mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv); + if (NS_WARN_IF(!mAudioChannelAgent)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr window = GetDOMWindow(); + if (NS_WARN_IF(!window)) { + return NS_ERROR_FAILURE; + } + + rv = mAudioChannelAgent->Init(window->GetCurrentInnerWindow(), + (int32_t)AudioChannelService::GetDefaultAudioChannel(), + this); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + nsCOMPtr agent = mAudioChannelAgent; + agent.forget(aAgent); + return NS_OK; +} + +NS_IMETHODIMP +nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted) +{ + // We just support mute/unmute + nsresult rv = SetMuted(aMuted); + NS_WARN_IF(NS_FAILED(rv)); + return rv; +} + +NS_IMETHODIMP +nsNPAPIPluginInstance::WindowAudioCaptureChanged() +{ + return NS_OK; +} + +nsresult +nsNPAPIPluginInstance::SetMuted(bool aIsMuted) +{ + if (RUNNING != mRunning) + return NS_OK; + + PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of mute state change this=%p\n",this)); + + if (!mPlugin || !mPlugin->GetLibrary()) + return NS_ERROR_FAILURE; + + NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); + + if (!pluginFunctions->setvalue) + return NS_ERROR_FAILURE; + + PluginDestructionGuard guard(this); + + NPError error; + NPBool value = static_cast(aIsMuted); + NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVmuteAudioBool, &value), this, + NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO); + return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE; +} diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index 21d4f312039..157f71b53f0 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -17,6 +17,7 @@ #include "nsHashKeys.h" #include #include "js/TypeDecls.h" +#include "nsIAudioChannelAgent.h" #ifdef MOZ_WIDGET_ANDROID #include "nsAutoPtr.h" #include "nsIRunnable.h" @@ -74,13 +75,14 @@ public: bool needUnschedule; }; -class nsNPAPIPluginInstance : public nsISupports +class nsNPAPIPluginInstance final : public nsIAudioChannelAgentCallback { private: typedef mozilla::PluginLibrary PluginLibrary; public: NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK nsresult Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType); nsresult Start(); @@ -117,6 +119,15 @@ public: nsPluginInstanceOwner* GetOwner(); void SetOwner(nsPluginInstanceOwner *aOwner); + bool HasAudioChannelAgent() const + { + return !!mAudioChannelAgent; + } + + nsresult GetOrCreateAudioChannelAgent(nsIAudioChannelAgent** aAgent); + + nsresult SetMuted(bool aIsMuted); + nsNPAPIPlugin* GetPlugin(); nsresult GetNPP(NPP * aNPP); @@ -404,6 +415,8 @@ private: uint32_t mCachedParamLength; char **mCachedParamNames; char **mCachedParamValues; + + nsCOMPtr mAudioChannelAgent; }; // On Android, we need to guard against plugin code leaking entries in the local