JavaScript — отправка события Node.js из функции обратного вызова C ++

В приложении Node.js я должен быть уведомлен, когда аудиоустройство по умолчанию было изменено. Эта программа будет использоваться в Windows 7.

В настоящее время я пытаюсь сделать это путем создания надстройки C ++ для узла, которая через метод IMMNotificationClient :: OnDefaultDeviceChanged из Windows Core Audio API генерирует событие, которое может быть получено отправителем события 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);

Я не уверен, как это сделать, поэтому вот мой вопрос: как передать событие в приложение Node.js через функцию обратного вызова C ++?

Я открыт для других решений до тех пор, пока они могут работать на ноде (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");
}

binding.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)

Этот код выдает ошибки и не компилируется, мы надеемся более подробно объяснить мою проблему.

0

Решение

Реализуйте один из классов Nan’s AsyncWorker. Для некоторого примера кода о том, как это сделать, посмотрите на этот ответ. после реализации работника назначьте функцию обратного вызова асинхронному работнику.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]