gpt4 book ai didi

javascript - 从 C++ 回调函数发出 Node.js 事件

转载 作者:行者123 更新时间:2023-11-30 05:00:24 27 4
gpt4 key购买 nike

在 Node.js 应用程序中,我需要在更改默认音频设备时收到通知。该程序将在 Windows 7 上使用。

目前,我正在尝试通过为 Node 制作一个 C++ 插件来实现这一点,该插件通过 Windows Core Audio API 的 IMMNotificationClient::OnDefaultDeviceChanged 方法发出一个事件,该事件可由 Node 事件发射器接收。

下面是 Windows Core Audio API 回调方法的示例:

HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceID)
{
//User written code that emits a node Event.
}

这是我希望在上述回调函数中包含的一些理想的 C++ 风格伪代码:

EventEmitter.emit(v8::String::NewFromUtf8("defaultDeviceChanged"), deviceName);

不过我不确定如何实现这一点,所以这是我的问题:如何通过 C++ 回调函数向 Node.js 应用程序发出事件?

我对其他解决方案持开放态度,只要它们可以在 Node 上本地运行(IE 通过附加组件),并且可以在 Windows 7 上运行,这意味着对 nircmd 等应用程序的外部调用不在考虑范围之内。

编辑

这是一些实验代码,试图帮助描述我在做什么:

AudioDeviceEmitter.h:

#pragma once

#include <stdio.h>
#include <wchar.h>
#include <tchar.h>
#include <time.h>
#include "windows.h"
#include "Mmdeviceapi.h"
#include "Propidl.h"
#include "Functiondiscoverykeys_devpkey.h"
#include <vector>
#include <string>
#include <comdef.h>
#define NAPI_DISABLE_CPP_EXCEPTIONS
#include <napi.h>
#include <vector>

class AudioDeviceEmitter : public Napi::ObjectWrap<AudioDeviceEmitter>, public IMMNotificationClient {
public:
static Napi::Object Init(Napi::Env env, Napi::Object exports);
AudioDeviceEmitter(const Napi::CallbackInfo& info);


Napi::Value AudioDeviceEmitter::enrollInNotifications(const Napi::CallbackInfo& info);
Napi::Value AudioDeviceEmitter::unenrollInNotifications(const Napi::CallbackInfo& info);
//WIN API
~AudioDeviceEmitter()
{
if (_pEnumerator != NULL) {
_pEnumerator->UnregisterEndpointNotificationCallback(this);
_pEnumerator->Release();
}
}


// IUnknown methods -- AddRef, Release, and QueryInterface

ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&_cRef);
}

ULONG STDMETHODCALLTYPE Release()
{
ULONG ulRef = InterlockedDecrement(&_cRef);
if (0 == ulRef)
{
delete this;
}
return ulRef;
}

HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid, VOID **ppvInterface)
{
if (IID_IUnknown == riid)
{
AddRef();
*ppvInterface = (IUnknown*)this;
}
else if (__uuidof(IMMNotificationClient) == riid)
{
AddRef();
*ppvInterface = (IMMNotificationClient*)this;
}
else
{
*ppvInterface = NULL;
return E_NOINTERFACE;
}
return S_OK;
}

// Callback methods for device-event notifications.
//------------THIS IS A FUNCTION I AM TRYING TO GET TO WORK----------
//------------It doesnt currently work, but hopefully shows----------
//------------ what I'm trying to accomplish ----------
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(
EDataFlow flow, ERole role,
LPCWSTR pwstrDeviceId)
{
if (flow == eRender) {
_locked = true;

std::string name = "";
IMMDevice * pDevice = NULL;
HRESULT hr = _pEnumerator->GetDevice(pwstrDeviceId, &pDevice);
if(SUCCEEDED(hr)){

name = getFriendlyNameString(pDevice);
pDevice->Release();
}

for(int i = 0; i < _stillEnrolled.size(); i++) {
if(_stillEnrolled.at(i)) {
Napi::CallbackInfo & info = _enrolledSessions.at(i);
Napi::Env env = info.Env();
Napi::Function emit = info.This().As<Napi::Object>()
.Get("emit").As<Napi::Function>();

emit.Call(info.This(), { Napi::String::New(env, "defaultDeviceChanged"),
Napi::String::New(env, name.c_str())});
}
}

_locked = false;
}
return S_OK;
}

HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId)
{
return S_OK;
};

HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(
LPCWSTR pwstrDeviceId,
DWORD dwNewState)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(
LPCWSTR pwstrDeviceId,
const PROPERTYKEY key)
{
return S_OK;
}

private:

std::string getFriendlyNameString(IMMDevice *pDevice) {
HRESULT hr;
IPropertyStore *pStore;
hr = pDevice->OpenPropertyStore(STGM_READ, &pStore);

PROPVARIANT variant;
PropVariantInit(&variant);
hr = pStore->GetValue(PKEY_Device_FriendlyName, &variant);
size_t strlen = wcslen((wchar_t *)variant.pwszVal);
int throwAwaylen;
char *pOutBuffer = (char *)malloc(strlen);
wcstombs_s((size_t *)&throwAwaylen, pOutBuffer, size, wideCharArray, size);

std::string toReturn = pOutBuffer;

free(pOutBuffer);

PropVariantClear(&variant);
pStore->Release();

return toReturn;

}

LONG _cRef;
IMMDeviceEnumerator *_pEnumerator;
static Napi::FunctionReference constructor;

std::vector<Napi::CallbackInfo> _enrolledSessions;
std::vector<bool> _stillEnrolled;
bool _locked;

};

AudioDeviceEmitter.cpp

#include "AudioDeviceEmitter.h"

Napi::FunctionReference AudioDeviceEmitter::constructor;

Napi::Object AudioDeviceEmitter::Init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);

Napi::Function func = DefineClass(env, "AudioDeviceEmitter", {
InstanceMethod("enrollInNotifications", &AudioDeviceEmitter::enrollInNotifications),
InstanceMethod("unenrollInNotifications", &AudioDeviceEmitter::unenrollInNotifications)
});

constructor = Napi::Persistent(func);
constructor.SuppressDestruct();

exports.Set("AudioDeviceEmitter", func);
return exports;
}

AudioDeviceEmitter::AudioDeviceEmitter(const Napi::CallbackInfo& info)
: Napi::ObjectWrap<AudioDeviceEmitter>(info), _locked(false), _cRef(1),
_pEnumerator(NULL)
{
HRESULT hr = CoInitialize(NULL);

hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&_pEnumerator);

_pEnumerator->RegisterEndpointNotificationCallback(this);
}

//------------THIS IS A FUNCTION I AM TRYING TO GET TO WORK----------
//------------It doesnt currently work, but hopefully shows----------
//------------ what I'm trying to accomplish ----------
Napi::Value AudioDeviceEmitter::enrollInNotifications(const Napi::CallbackInfo& info) {
while(_locked){}

_locked = true;
int currentPos = _enrolledSessions.size();
_enrolledSessions.push_back(info);
_stillEnrolled.push_back(true);
_locked = false;

while(_stillEnrolled.at(currentPos)){}

return Napi::String::New(info.Env(), "OK");
}


//------------THIS IS A FUNCTION I AM TRYING TO GET TO WORK----------
//------------It doesnt currently work, but hopefully shows----------
//------------ what I'm trying to accomplish ----------
Napi::Value AudioDeviceEmitter::unenrollInNotifications(const Napi::CallbackInfo& info) {
while(_locked){}

for(int i = 0; i < _enrolledSessions.size(); i++) {
if (info.This() == _enrolledSessions.at(i).This()) {
_stillEnrolled.at(i) = false;
}
}

return Napi::String::New(info.Env(), "OK");
}

绑定(bind).cpp:

#include <napi.h>
#include "AudioDeviceEmitter.h"

Napi::Object InitNAPI(Napi::Env env, Napi::Object exports) {
AudioDeviceEmitter::Init(env, exports);
return exports;
}

NODE_API_MODULE(WinDefaultAudioDevice, InitNAPI)

此代码会抛出错误且无法编译,希望能更全面地解释我的问题。

最佳答案

实现 Nan 的 AsyncWorker 类之一。有关如何执行此操作的一些示例代码,look at this answer .实现 worker 后,为异步 worker 分配一个回调函数。

关于javascript - 从 C++ 回调函数发出 Node.js 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50822041/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com