mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 16:25:38 +00:00
Bug 1251202 - Implement Default Audio Device Notifications for NPAPI plugins on Windows. r=jimm
Adds plugin variables NPPVpluginRequiresAudioDeviceChanges and NPNVaudioDeviceChangeDetails on Windows. --HG-- extra : rebase_source : ff18bbca9772352b18be1dfcde90570775e8d5cc
This commit is contained in:
parent
f0fc76e6d7
commit
17683f933c
@ -259,6 +259,26 @@ typedef struct
|
||||
|
||||
#endif /* XP_UNIX */
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/*
|
||||
* Windows specific structures and definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Information about the default audio device. These values share meaning with
|
||||
* the parameters to the Windows API IMMNotificationClient object.
|
||||
* This is the value of the NPNVaudioDeviceChangeDetails variable.
|
||||
*/
|
||||
typedef struct _NPAudioDeviceChangeDetails
|
||||
{
|
||||
int32_t flow;
|
||||
int32_t role;
|
||||
const wchar_t* defaultDevice; // this pointer is only valid during the call
|
||||
// to NPPSetValue.
|
||||
} NPAudioDeviceChangeDetails;
|
||||
|
||||
#endif /* XP_WIN */
|
||||
|
||||
typedef enum {
|
||||
NPDrawingModelDUMMY
|
||||
#if defined(XP_MACOSX)
|
||||
@ -379,6 +399,10 @@ typedef enum {
|
||||
#endif
|
||||
/* Notification that the plugin just started or stopped playing audio */
|
||||
, NPPVpluginIsPlayingAudio = 4000
|
||||
#if defined(XP_WIN)
|
||||
/* Notification that the plugin requests notification when the default audio device has changed */
|
||||
, NPPVpluginRequiresAudioDeviceChanges = 4001
|
||||
#endif
|
||||
|
||||
} NPPVariable;
|
||||
|
||||
@ -442,6 +466,9 @@ typedef enum {
|
||||
Cocoa text input specification. */
|
||||
#endif
|
||||
, NPNVmuteAudioBool = 4000 /* Request that the browser wants to mute or unmute the plugin */
|
||||
#if defined(XP_WIN)
|
||||
, NPNVaudioDeviceChangeDetails = 4001 /* Provides information about the new default audio device */
|
||||
#endif
|
||||
#if defined(XP_MACOSX)
|
||||
, NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports
|
||||
CA model compositing */
|
||||
|
@ -14,6 +14,7 @@ using NPNVariable from "npapi.h";
|
||||
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
||||
using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using struct nsID from "nsID.h";
|
||||
using struct mozilla::plugins::NPAudioDeviceChangeDetailsIPC from "mozilla/plugins/PluginMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
@ -106,6 +107,8 @@ child:
|
||||
|
||||
async SettingChanged(PluginSettings settings);
|
||||
|
||||
async NPP_SetValue_NPNVaudioDeviceChangeDetails(NPAudioDeviceChangeDetailsIPC changeDetails);
|
||||
|
||||
parent:
|
||||
async NP_InitializeResult(NPError aError);
|
||||
|
||||
@ -159,6 +162,9 @@ parent:
|
||||
|
||||
intr GetKeyState(int32_t aVirtKey)
|
||||
returns (int16_t aState);
|
||||
|
||||
intr NPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(bool shouldRegister)
|
||||
returns (NPError result);
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
@ -224,6 +224,11 @@ PluginInstanceChild::~PluginInstanceChild()
|
||||
if (GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) {
|
||||
ClearUnityHooks();
|
||||
}
|
||||
// In the event that we registered for audio device changes, stop.
|
||||
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
|
||||
if (chromeInstance) {
|
||||
NPError rv = chromeInstance->PluginRequiresAudioDeviceChanges(this, false);
|
||||
}
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_COCOA)
|
||||
if (mShColorSpace) {
|
||||
@ -684,6 +689,23 @@ PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue)
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
case NPPVpluginRequiresAudioDeviceChanges: {
|
||||
// Many other NPN_SetValue variables are forwarded to our
|
||||
// PluginInstanceParent, which runs on a content process. We
|
||||
// instead forward this message to the PluginModuleParent, which runs
|
||||
// on the chrome process. This is because our audio
|
||||
// API calls should run the chrome proc, not content.
|
||||
NPError rv = NPERR_GENERIC_ERROR;
|
||||
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
|
||||
if (chromeInstance) {
|
||||
rv = chromeInstance->PluginRequiresAudioDeviceChanges(this,
|
||||
(NPBool)(intptr_t)aValue);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
MOZ_LOG(GetPluginLog(), LogLevel::Warning,
|
||||
("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)",
|
||||
@ -856,6 +878,18 @@ PluginInstanceChild::AnswerNPP_SetValue_NPNVmuteAudioBool(const bool& value,
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
NPError
|
||||
PluginInstanceChild::DefaultAudioDeviceChanged(NPAudioDeviceChangeDetails& details)
|
||||
{
|
||||
if (!mPluginIface->setvalue) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
return mPluginIface->setvalue(GetNPP(), NPNVaudioDeviceChangeDetails, (void*)&details);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool
|
||||
PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event,
|
||||
int16_t* handled)
|
||||
|
@ -278,6 +278,10 @@ public:
|
||||
const NativeEventData& aKeyEventData,
|
||||
const bool& aIsConsumed) override;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
NPError DefaultAudioDeviceChanged(NPAudioDeviceChangeDetails& details);
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class PluginModuleChild;
|
||||
|
||||
|
@ -98,6 +98,17 @@ struct NPRemoteWindow
|
||||
#endif
|
||||
};
|
||||
|
||||
// This struct is like NPAudioDeviceChangeDetails, only it uses a
|
||||
// std::wstring instead of a const wchar_t* for the defaultDevice.
|
||||
// This gives us the necessary memory-ownership semantics without
|
||||
// requiring C++ objects in npapi.h.
|
||||
struct NPAudioDeviceChangeDetailsIPC
|
||||
{
|
||||
int32_t flow;
|
||||
int32_t role;
|
||||
std::wstring defaultDevice;
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
typedef HWND NativeWindowHandle;
|
||||
#elif defined(MOZ_X11)
|
||||
@ -152,6 +163,10 @@ NPPVariableToString(NPPVariable aVar)
|
||||
VARSTR(NPPVpluginEventModel);
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
VARSTR(NPPVpluginRequiresAudioDeviceChanges);
|
||||
#endif
|
||||
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
@ -182,6 +197,10 @@ NPNVariableToString(NPNVariable aVar)
|
||||
VARSTR(NPNVprivateModeBool);
|
||||
VARSTR(NPNVdocumentOrigin);
|
||||
|
||||
#ifdef XP_WIN
|
||||
VARSTR(NPNVaudioDeviceChangeDetails);
|
||||
#endif
|
||||
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
@ -674,6 +693,40 @@ struct ParamTraits<NPCoordinateSpace>
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::plugins::NPAudioDeviceChangeDetailsIPC>
|
||||
{
|
||||
typedef mozilla::plugins::NPAudioDeviceChangeDetailsIPC paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.flow);
|
||||
WriteParam(aMsg, aParam.role);
|
||||
WriteParam(aMsg, aParam.defaultDevice);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
int32_t flow, role;
|
||||
std::wstring defaultDevice;
|
||||
if (ReadParam(aMsg, aIter, &flow) &&
|
||||
ReadParam(aMsg, aIter, &role) &&
|
||||
ReadParam(aMsg, aIter, &defaultDevice)) {
|
||||
aResult->flow = flow;
|
||||
aResult->role = role;
|
||||
aResult->defaultDevice = defaultDevice;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%d, %d, %S]", aParam.flow, aParam.role,
|
||||
aParam.defaultDevice.c_str()));
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace IPC */
|
||||
|
||||
|
||||
|
@ -2565,3 +2565,62 @@ PluginModuleChild::RecvGatherProfile()
|
||||
Unused << SendProfile(profileCString);
|
||||
return true;
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginModuleChild::PluginRequiresAudioDeviceChanges(
|
||||
PluginInstanceChild* aInstance,
|
||||
NPBool aShouldRegister)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
// Maintain a set of PluginInstanceChildren that we need to tell when the
|
||||
// default audio device has changed.
|
||||
NPError rv = NPERR_NO_ERROR;
|
||||
if (aShouldRegister) {
|
||||
if (mAudioNotificationSet.IsEmpty()) {
|
||||
// We are registering the first plugin. Notify the PluginModuleParent
|
||||
// that it needs to start sending us audio device notifications.
|
||||
if (!CallNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
||||
aShouldRegister, &rv)) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
if (rv == NPERR_NO_ERROR) {
|
||||
mAudioNotificationSet.PutEntry(aInstance);
|
||||
}
|
||||
}
|
||||
else if (!mAudioNotificationSet.IsEmpty()) {
|
||||
mAudioNotificationSet.RemoveEntry(aInstance);
|
||||
if (mAudioNotificationSet.IsEmpty()) {
|
||||
// We released the last plugin. Unregister from the PluginModuleParent.
|
||||
if (!CallNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
||||
aShouldRegister, &rv)) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
NS_RUNTIMEABORT("PluginRequiresAudioDeviceChanges is not available on this platform.");
|
||||
return NPERR_GENERIC_ERROR;
|
||||
#endif // XP_WIN
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::RecvNPP_SetValue_NPNVaudioDeviceChangeDetails(
|
||||
const NPAudioDeviceChangeDetailsIPC& detailsIPC)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
NPAudioDeviceChangeDetails details;
|
||||
details.flow = detailsIPC.flow;
|
||||
details.role = detailsIPC.role;
|
||||
details.defaultDevice = detailsIPC.defaultDevice.c_str();
|
||||
for (auto iter = mAudioNotificationSet.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
PluginInstanceChild* pluginInst = iter.Get()->GetKey();
|
||||
pluginInst->DefaultAudioDeviceChanged(details);
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
NS_RUNTIMEABORT("NPP_SetValue_NPNVaudioDeviceChangeDetails is a Windows-only message");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
@ -239,6 +239,11 @@ public:
|
||||
|
||||
const PluginSettings& Settings() const { return mCachedSettings; }
|
||||
|
||||
NPError PluginRequiresAudioDeviceChanges(PluginInstanceChild* aInstance,
|
||||
NPBool aShouldRegister);
|
||||
bool RecvNPP_SetValue_NPNVaudioDeviceChangeDetails(
|
||||
const NPAudioDeviceChangeDetailsIPC& detailsIPC) override;
|
||||
|
||||
private:
|
||||
NPError DoNP_Initialize(const PluginSettings& aSettings);
|
||||
void AddQuirk(PluginQuirks quirk) {
|
||||
@ -323,6 +328,13 @@ private:
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
typedef nsTHashtable<nsPtrHashKey<PluginInstanceChild>> PluginInstanceSet;
|
||||
// Set of plugins that have registered to be notified when the audio device
|
||||
// changes.
|
||||
PluginInstanceSet mAudioNotificationSet;
|
||||
#endif
|
||||
|
||||
public: // called by PluginInstanceChild
|
||||
/**
|
||||
* Dealloc an NPObject after last-release or when the associated instance
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "mozilla/plugins/PluginSurfaceParent.h"
|
||||
#include "mozilla/widget/AudioSession.h"
|
||||
#include "PluginHangUIParent.h"
|
||||
#include "PluginUtilsWin.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
@ -776,6 +777,12 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
|
||||
ShutdownPluginProfiling();
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
// If we registered for audio notifications, stop.
|
||||
mozilla::plugins::PluginUtilsWin::RegisterForAudioDeviceChanges(this,
|
||||
false);
|
||||
#endif
|
||||
|
||||
if (!mShutdown) {
|
||||
NS_WARNING("Plugin host deleted the module without shutting down.");
|
||||
NPError err;
|
||||
@ -1906,6 +1913,26 @@ PluginModuleParent::NPP_SetValue(NPP instance, NPNVariable variable,
|
||||
RESOLVE_AND_CALL(instance, NPP_SetValue(variable, value));
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChromeParent::AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
||||
const bool& shouldRegister, NPError* result)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
*result = NPERR_NO_ERROR;
|
||||
nsresult err =
|
||||
mozilla::plugins::PluginUtilsWin::RegisterForAudioDeviceChanges(this,
|
||||
shouldRegister);
|
||||
if (err != NS_OK) {
|
||||
*result = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
NS_RUNTIMEABORT("NPPVpluginRequiresAudioDeviceChanges is not valid on this platform.");
|
||||
*result = NPERR_GENERIC_ERROR;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
|
||||
{
|
||||
@ -3135,6 +3162,17 @@ PluginModuleParent::EnsureTextureAllocator()
|
||||
return mTextureAllocator;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PluginModuleParent::AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
||||
const bool& shouldRegister,
|
||||
NPError* result) {
|
||||
NS_RUNTIMEABORT("SetValue_NPPVpluginRequiresAudioDeviceChanges is only valid "
|
||||
"with PluginModuleChromeParent");
|
||||
*result = NPERR_GENERIC_ERROR;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
|
||||
// We only add the crash reporter to subprocess which have the filename
|
||||
|
@ -198,6 +198,11 @@ protected:
|
||||
static BrowserStreamParent* StreamCast(NPP instance, NPStream* s,
|
||||
PluginAsyncSurrogate** aSurrogate = nullptr);
|
||||
|
||||
virtual bool
|
||||
AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
||||
const bool& shouldRegister,
|
||||
NPError* result) override;
|
||||
|
||||
protected:
|
||||
void SetChildTimeout(const int32_t aChildTimeout);
|
||||
static void TimeoutChanged(const char* aPref, void* aModule);
|
||||
@ -569,6 +574,11 @@ private:
|
||||
|
||||
static void CachedSettingChanged(const char* aPref, void* aModule);
|
||||
|
||||
virtual bool
|
||||
AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
||||
const bool& shouldRegister,
|
||||
NPError* result) override;
|
||||
|
||||
PluginProcessParent* mSubprocess;
|
||||
uint32_t mPluginId;
|
||||
|
||||
|
237
dom/plugins/ipc/PluginUtilsWin.cpp
Normal file
237
dom/plugins/ipc/PluginUtilsWin.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* PluginUtilsWin.cpp - top-level Windows plugin management code */
|
||||
|
||||
#include <mmdeviceapi.h>
|
||||
#include "PluginUtilsWin.h"
|
||||
#include "PluginModuleParent.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
namespace PluginUtilsWin {
|
||||
|
||||
typedef nsTHashtable<nsPtrHashKey<PluginModuleParent>> PluginModuleSet;
|
||||
StaticMutex sMutex;
|
||||
|
||||
class AudioDeviceChangedRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
explicit AudioDeviceChangedRunnable(const PluginModuleSet* aAudioNotificationSet,
|
||||
NPAudioDeviceChangeDetailsIPC aChangeDetails) :
|
||||
mChangeDetails(aChangeDetails)
|
||||
, mAudioNotificationSet(aAudioNotificationSet)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
PLUGIN_LOG_DEBUG(("Notifying %d plugins of audio device change.",
|
||||
mAudioNotificationSet->Count()));
|
||||
|
||||
for (auto iter = mAudioNotificationSet->ConstIter(); !iter.Done(); iter.Next()) {
|
||||
PluginModuleParent* pluginModule = iter.Get()->GetKey();
|
||||
pluginModule->SendNPP_SetValue_NPNVaudioDeviceChangeDetails(mChangeDetails);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
NPAudioDeviceChangeDetailsIPC mChangeDetails;
|
||||
const PluginModuleSet* mAudioNotificationSet;
|
||||
};
|
||||
|
||||
class AudioNotification : public IMMNotificationClient
|
||||
{
|
||||
public:
|
||||
AudioNotification() :
|
||||
mRefCt(1)
|
||||
, mIsRegistered(false)
|
||||
{
|
||||
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
|
||||
NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&mDeviceEnum));
|
||||
if (FAILED(hr)) {
|
||||
mDeviceEnum = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
hr = mDeviceEnum->RegisterEndpointNotificationCallback(this);
|
||||
if (FAILED(hr)) {
|
||||
mDeviceEnum->Release();
|
||||
mDeviceEnum = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mIsRegistered = true;
|
||||
}
|
||||
|
||||
~AudioNotification()
|
||||
{
|
||||
MOZ_ASSERT(!mIsRegistered,
|
||||
"Destroying AudioNotification without first calling Unregister");
|
||||
if (mDeviceEnum) {
|
||||
mDeviceEnum->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// IMMNotificationClient Implementation
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR device_id) override
|
||||
{
|
||||
NPAudioDeviceChangeDetailsIPC changeDetails;
|
||||
changeDetails.flow = (int32_t)flow;
|
||||
changeDetails.role = (int32_t)role;
|
||||
changeDetails.defaultDevice = std::wstring(device_id);
|
||||
|
||||
// Make sure that plugin is notified on the main thread.
|
||||
RefPtr<AudioDeviceChangedRunnable> runnable =
|
||||
new AudioDeviceChangedRunnable(&mAudioNotificationSet, changeDetails);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDeviceAdded(LPCWSTR device_id) override
|
||||
{
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDeviceRemoved(LPCWSTR device_id) override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDeviceStateChanged(LPCWSTR device_id, DWORD new_state) override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnPropertyValueChanged(LPCWSTR device_id, const PROPERTYKEY key) override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// IUnknown Implementation
|
||||
ULONG STDMETHODCALLTYPE
|
||||
AddRef() override
|
||||
{
|
||||
return InterlockedIncrement(&mRefCt);
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE
|
||||
Release() override
|
||||
{
|
||||
ULONG ulRef = InterlockedDecrement(&mRefCt);
|
||||
if (0 == ulRef) {
|
||||
delete this;
|
||||
}
|
||||
return ulRef;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
QueryInterface(REFIID riid, VOID **ppvInterface) override
|
||||
{
|
||||
if (__uuidof(IUnknown) == riid) {
|
||||
AddRef();
|
||||
*ppvInterface = (IUnknown*)this;
|
||||
} else if (__uuidof(IMMNotificationClient) == riid) {
|
||||
AddRef();
|
||||
*ppvInterface = (IMMNotificationClient*)this;
|
||||
} else {
|
||||
*ppvInterface = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* A Valid instance must be Unregistered before Releasing it.
|
||||
*/
|
||||
void Unregister()
|
||||
{
|
||||
if (mDeviceEnum) {
|
||||
mDeviceEnum->UnregisterEndpointNotificationCallback(this);
|
||||
}
|
||||
mIsRegistered = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* True whenever the notification server is set to report events to this object.
|
||||
*/
|
||||
bool IsRegistered() {
|
||||
return mIsRegistered;
|
||||
}
|
||||
|
||||
void AddModule(PluginModuleParent* aModule) {
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
mAudioNotificationSet.PutEntry(aModule);
|
||||
}
|
||||
|
||||
void RemoveModule(PluginModuleParent* aModule) {
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
mAudioNotificationSet.RemoveEntry(aModule);
|
||||
}
|
||||
|
||||
/*
|
||||
* Are any modules registered for audio notifications?
|
||||
*/
|
||||
bool HasModules() {
|
||||
return !mAudioNotificationSet.IsEmpty();
|
||||
}
|
||||
|
||||
private:
|
||||
bool mIsRegistered; // only used to make sure that Unregister is called before destroying a Valid instance.
|
||||
LONG mRefCt;
|
||||
IMMDeviceEnumerator* mDeviceEnum;
|
||||
|
||||
// Set of plugin modules that have registered to be notified when the audio device
|
||||
// changes.
|
||||
PluginModuleSet mAudioNotificationSet;
|
||||
}; // class AudioNotification
|
||||
|
||||
// callback that gets notified of audio device events, or NULL
|
||||
AudioNotification* sAudioNotification = nullptr;
|
||||
|
||||
nsresult
|
||||
RegisterForAudioDeviceChanges(PluginModuleParent* aModuleParent, bool aShouldRegister)
|
||||
{
|
||||
// Hold the AudioNotification singleton iff there are PluginModuleParents
|
||||
// that are subscribed to it.
|
||||
if (aShouldRegister) {
|
||||
if (!sAudioNotification) {
|
||||
// We are registering the first module. Create the singleton.
|
||||
sAudioNotification = new AudioNotification();
|
||||
if (!sAudioNotification->IsRegistered()) {
|
||||
PLUGIN_LOG_DEBUG(("Registered for plugin audio device notification failed."));
|
||||
sAudioNotification->Release();
|
||||
sAudioNotification = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
PLUGIN_LOG_DEBUG(("Registered for plugin audio device notification."));
|
||||
}
|
||||
sAudioNotification->AddModule(aModuleParent);
|
||||
}
|
||||
else if (!aShouldRegister && sAudioNotification) {
|
||||
sAudioNotification->RemoveModule(aModuleParent);
|
||||
if (!sAudioNotification->HasModules()) {
|
||||
// We have removed the last module from the notification mechanism
|
||||
// so we can destroy the singleton.
|
||||
PLUGIN_LOG_DEBUG(("Unregistering for plugin audio device notification."));
|
||||
sAudioNotification->Unregister();
|
||||
sAudioNotification->Release();
|
||||
sAudioNotification = nullptr;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace PluginUtilsWin
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
23
dom/plugins/ipc/PluginUtilsWin.h
Normal file
23
dom/plugins/ipc/PluginUtilsWin.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:set ts=2 sts=2 sw=2 et cin:
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef dom_plugins_PluginUtilsWin_h
|
||||
#define dom_plugins_PluginUtilsWin_h 1
|
||||
|
||||
#include "npapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
namespace PluginUtilsWin {
|
||||
|
||||
nsresult RegisterForAudioDeviceChanges(PluginModuleParent* aModuleParent,
|
||||
bool aShouldRegister);
|
||||
|
||||
} // namespace PluginUtilsWin
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
||||
#endif //dom_plugins_PluginUtilsWin_h
|
@ -102,6 +102,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
UNIFIED_SOURCES += [
|
||||
'D3D11SurfaceHolder.cpp',
|
||||
'PluginUtilsWin.cpp'
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
|
Loading…
Reference in New Issue
Block a user