Kinect Face Tracking getStatus() - c++

I am working on a face tracking program, however my getStatus() call is returning 0xcccccccc which I think is uninitialized data? Below is some of the code. I can display a color image on the screen so I am getting data ok. Can anyone give me any pointers?
IFTResult* fTrackingResult = NULL;
bool initialseFaceTracker() {
tracker = FTCreateFaceTracker();
if (!tracker) {
return false;
}
FT_CAMERA_CONFIG colorConfig = {640, 480, NUI_CAMERA_COLOR_NOMINAL_FOCAL_LENGTH_IN_PIXELS};
FT_CAMERA_CONFIG depthConfig = {320, 240, NUI_CAMERA_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS};
HRESULT hr = tracker->Initialize(&colorConfig, &depthConfig, NULL, NULL);
if ( FAILED(hr) ) {
return false;
}
hr = tracker->CreateFTResult( &fTrackingResult );
if (FAILED(hr)) {
return false;
}
IFTImage* colorFrame = FTCreateImage();
IFTImage* depthFrame = FTCreateImage();
if (!colorFrame || !depthFrame) {
return false;
}
hr = colorFrame->Attach(640, 480, &colorImageData, FTIMAGEFORMAT_UINT8_R8G8B8, 640*4);
if (FAILED(hr)) {
return false;
}
hr = depthFrame->Attach(320, 240, &depthData, FTIMAGEFORMAT_UINT16_D13P3, 320*2);
if (FAILED(hr)) {
return false;
}
sensorData.pVideoFrame = colorFrame;
sensorData.pDepthFrame = depthFrame;
sensorData.ZoomFactor = 1.0f;
sensorData.ViewOffset.x = 0;
sensorData.ViewOffset.y = 0;
return true;
}
bool updateFaceTacking() {
if(!gotFaceTracking) {
HRESULT hr = tracker->StartTracking(&sensorData, NULL, NULL, fTrackingResult);
if (SUCCEEDED(hr)){
HRESULT hr2 = fTrackingResult -> GetStatus();
if (SUCCEEDED(hr2)) {
gotFaceTracking = true;
}
}
} else {
HRESULT hr = tracker->ContinueTracking(&sensorData, NULL, fTrackingResult);
if( FAILED(fTrackingResult->GetStatus()))
gotFaceTracking = false;
}
return true;
}

you have TO place facetracker.lib and the other .dlls that come with one of the examples in your debug folder. Let me know if this helps

Related

Getting bytes from GraphFilter SampleGrabber to Audio raw data WinApi

I am having a big issue getting raw audio data from the SampleGrabber GraphFilter and writing it to an audio file in the proper format.
What i'm trying to achieve is:
grabbing the data from: Microphone->SampleGrabber->Null Rendrer
Write the raw data captured to a proper audio file (MP3\AVI\WAVE)
Some questions:
Am I setting the proper MediaType for the SampleGrabber?
How can you compress the audio data to a proper audio file?
My current code below:
struct sRecortdingData {
std::vector<BYTE> recordingData;
double totalRecordingTime;
};
class CFakeCallback : public ISampleGrabberCB
{
public:
sRecortdingData sRecording;
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP_(HRESULT __stdcall) QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_ISampleGrabberCB || riid == IID_IUnknown)
{
*ppv = (void*) static_cast<ISampleGrabberCB*>(this);
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(HRESULT __stdcall) SampleCB(double SampleTime, IMediaSample* pSample)
{
return S_OK;
}
STDMETHODIMP_(HRESULT __stdcall) BufferCB(double SampleTime, BYTE* pBuffer, long BufferLen)
{
sRecording.recordingData.push_back(*pBuffer);
sRecording.totalRecordingTime = SampleTime;
return S_OK;
}
};
void Microphone::RecordAudio()
{
HRESULT hr;
AM_MEDIA_TYPE mt;
long recordingEventCode;
IMediaControl* pMediaControl = NULL;
ISampleGrabber* pISampleGrabber = NULL;
IBaseFilter* pSampleGrabberFilter;
IGraphBuilder* pGraphBuilder = NULL;
IMediaEventEx* pEvent = NULL;
IBaseFilter* pMicrophoneFilter = NULL;
ISampleGrabber* pSampleGrabber = NULL;
ICreateDevEnum* pDeviceEnum = NULL;
IBaseFilter* pNullRender = NULL;
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
// Filter graph
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraphBuilder));
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
// Device enum
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDeviceEnum));
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
// Null renderer
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pNullRender));
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
// Get the even control
hr = pGraphBuilder->QueryInterface(IID_PPV_ARGS(&pEvent));
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
// Sample Grabber
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSampleGrabberFilter));
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
// Get Media Control
hr = pGraphBuilder->QueryInterface(IID_PPV_ARGS(&pMediaControl));
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
// Setup input device filter
pMicrophoneFilter = Microphone::SetupDeviceFilter(CLSID_AudioInputDeviceCategory, pGraphBuilder, pDeviceEnum,
Utils::s2ws("My Microphone");
if (pMicrophoneFilter == NULL) {
HR_Failed(hr);
return;
}
// Setup sample grabber filter
pSampleGrabberFilter = Microphone::SetupDeviceFilter(CLSID_LegacyAmFilterCategory,
pGraphBuilder, pDeviceEnum, L"SampleGrabber");
if (pSampleGrabberFilter == NULL) {
HR_Failed(hr);
return;
}
// Connect both pins together
Device_Connect(pMicrophoneFilter, pSampleGrabberFilter);
// Setup null renderer filter
pNullRender = Microphone::SetupDeviceFilter(CLSID_LegacyAmFilterCategory,
pGraphBuilder, pDeviceEnum, L"Null Renderer");
if (pNullRender == NULL) {
HR_Failed(hr);
return;
}
// Connect both pins together
Device_Connect(pSampleGrabberFilter, pNullRender);
// Get the ISampleGranner interface
hr = pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (LPVOID*)&pISampleGrabber);
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
hr = pISampleGrabber->SetCallback(&CB, 1);
ZeroMemory(&mt, sizeof(mt));
mt.majortype = MEDIATYPE_Audio;
mt.subtype = MEDIASUBTYPE_PCM;
// Set the media type
hr = pISampleGrabber->SetMediaType(&mt);
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
pISampleGrabber->SetBufferSamples(FALSE);
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
hr = pMediaControl->Run();
if (FAILED(hr))
{
HR_Failed(hr);
return;
}
DWORD recordingTime = 20000;
hr = pEvent->WaitForCompletion(recordingTime, &recordingEventCode);
std::string str(CB.sRecording.recordingData.begin(), CB.sRecording.recordingData.end());
// Do something with the data from callback and write it to audio file
}

How can I prevent Direct-X 12 from multi-adaptering? [duplicate]

I'm coding a C++ game from scratch using the Direct-X 12 API.
I'm using a few tutorials: Braynzar Soft Direct-X 12 tutorial, Alian Direct-X 12 and a few others.
Each one I use runs and has no errors. But I have a slight problem.
In professional games and game engines, they can use a dedicated GPU to run their programs and sometimes at a low performance. BUT, when I use this tutorials or I code it myself, it uses both of my GPUs simultaneously. Why is that? Is there some bug within the code? Does Direct-X 12 just multi-GPU automatically? Can I prevent this and how? There wouldn't be a problem with this, but I would like, if possible, to only use on GPU.
Simple code:
int32_t CALLBACK wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int32_t)
{
HRESULT ReturnCode = S_OK;
#ifdef _SCPDebug
ID3D12Debug3* D3D12DebugInterface = nullptr;
IDXGIInfoQueue* DXGIDebugInfoQueue = nullptr;
ReturnCode = D3D12GetDebugInterface(IID_PPV_ARGS(&D3D12DebugInterface));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
D3D12DebugInterface->EnableDebugLayer();
D3D12DebugInterface->SetEnableGPUBasedValidation(TRUE);
ReturnCode = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&DXGIDebugInfoQueue));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = DXGIDebugInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = DXGIDebugInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
#endif
IDXGIFactory7* DXGIFactory = nullptr;
#ifdef _SCPDebug
ReturnCode = CreateDXGIFactory2(1, IID_PPV_ARGS(&DXGIFactory));
#else
ReturnCode = CreateDXGIFactory2(0, IID_PPV_ARGS(&DXGIFactory));
#endif
if (ReturnCode != S_OK)
{
return ReturnCode;
}
BOOL SupportsVariableRefreshRate = FALSE;
ReturnCode = DXGIFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &SupportsVariableRefreshRate, sizeof(BOOL));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
IDXGIAdapter4* DXGIAdapter = nullptr;
ReturnCode = DXGIFactory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&DXGIAdapter));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ID3D12Device8* D3D12Device = nullptr;
#ifdef _SCPDebug
ID3D12InfoQueue* D3D12DeviceDebugInfoQueue = nullptr;
#endif
ReturnCode = D3D12CreateDevice(DXGIAdapter, D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS(&D3D12Device));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12Device->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Device8");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
#ifdef _SCPDebug
ReturnCode = D3D12Device->QueryInterface(&D3D12DeviceDebugInfoQueue);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12DeviceDebugInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12DeviceDebugInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
#endif
ID3D12DescriptorHeap* D3D12DSDescriptorHeap = nullptr;
ID3D12Resource2* D3D12DS = nullptr;
D3D12_DESCRIPTOR_HEAP_DESC DescriptorHeapDesc = {};
DescriptorHeapDesc.NumDescriptors = 1;
DescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
DescriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ReturnCode = D3D12Device->CreateDescriptorHeap(&DescriptorHeapDesc, IID_PPV_ARGS(&D3D12DSDescriptorHeap));
if (FAILED(ReturnCode))
{
return ReturnCode;
}
ReturnCode = D3D12DSDescriptorHeap->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Depth Stencil Descriptor Heap");
if (FAILED(ReturnCode))
{
return ReturnCode;
}
D3D12_CLEAR_VALUE OptimizedDepthClearValue;
OptimizedDepthClearValue.DepthStencil.Depth = 1.0f;
OptimizedDepthClearValue.DepthStencil.Stencil = 0;
OptimizedDepthClearValue.Format = DXGI_FORMAT_D32_FLOAT;
D3D12_HEAP_PROPERTIES HeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
D3D12_RESOURCE_DESC HeapDesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, 1920, 1080, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);
ReturnCode = D3D12Device->CreateCommittedResource(&HeapProperties, D3D12_HEAP_FLAG_NONE, &HeapDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &OptimizedDepthClearValue, IID_PPV_ARGS(D3D12DS));
if (FAILED(ReturnCode))
{
return ReturnCode;
}
ReturnCode = D3D12DS->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Depth Stencil Heap");
if (FAILED(ReturnCode))
{
return ReturnCode;
}
D3D12_DEPTH_STENCIL_VIEW_DESC DepthStencilViewDesc = {};
DepthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT;
DepthStencilViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
DepthStencilViewDesc.Flags = D3D12_DSV_FLAG_NONE;
D3D12Device->CreateDepthStencilView(D3D12DS, &DepthStencilViewDesc, D3D12DSDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
ID3D12Fence1* D3D12Fence = nullptr;
uint64_t FenceValue = 0ULL;
HANDLE FenceEvent = nullptr;
ReturnCode = D3D12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&D3D12Fence));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12Fence->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Sync::Fence");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
HANDLE FenceEvent = CreateEventW(nullptr, FALSE, FALSE, L"SCP-Site Breach::Engine::Direct-X 12::Sync::Fence Event");
if (FenceEvent == nullptr)
{
return E_UNEXPECTED;
}
ID3D12RootSignature* D3D12RootSignature = nullptr;
{
D3D12_ROOT_SIGNATURE_DESC1 Desc = {};
Desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
Desc.NumParameters = 0;
Desc.NumStaticSamplers = 0;
Desc.pParameters = nullptr;
Desc.pStaticSamplers = nullptr;
D3D12_VERSIONED_ROOT_SIGNATURE_DESC RootSignatureDescVersion = {};
RootSignatureDescVersion.Desc_1_1 = Desc;
RootSignatureDescVersion.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
ID3D10Blob* D3D12SignatureBlob = nullptr;
ID3D10Blob* D3D12ErrorBlob = nullptr;
ReturnCode = D3D12SerializeVersionedRootSignature(&RootSignatureDescVersion, &D3D12SignatureBlob &D3D12ErrorBlob);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12Device->CreateRootSignature(0, D3D12SignatureBlob->GetBufferPointer(), D3D12SignatureBlob->GetBufferSize(), IID_PPV_ARGS(&D3D12RootSignature));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode =D3D12RootSignature->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Root Signature");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
D3D12SignatureBlob->Release();
D3D12SignatureBlob = nullptr;
}
D3D12_SHADER_BYTECODE D3D12PixelShader = {};
D3D12_SHADER_BYTECODE D3D12VertexShader = {};
std::ifstream PixelShader("PixelShader.cso", std::ios_base::binary | std::ios_base::in);
auto FileSize = PixelShader.tellg();
PixelShader.seekg(0, std::iostream::end);
FileSize += PixelShader.tellg() - FileSize;
PixelShader.seekg(0, std::iostream::beg);
std::ifstream VertexShader("VertexShader.cso", std::ios_base::binary | std::ios_base::in);
auto FileSize2 = VertexShader.tellg();
VertexShader.seekg(0, std::iostream::end);
FileSize2 += VertexShader.tellg() - FileSize2;
VertexShader.seekg(0, std::iostream::beg);
D3D12PixelShader.BytecodeLength = msl::utilities::SafeInt<SIZE_T>(FileSize.operator long long());
D3D12PixelShader.pShaderBytecode = malloc(D3D12PixelShader.BytecodeLength);
PixelShader.read(reinterpret_cast<char*>(const_cast<void*>(D3D12PixelShader.pShaderBytecode)), msl::utilities::SafeInt<long long>(D3D12PixelShader.BytecodeLength));
D3D12VertexShader.BytecodeLength = msl::utilities::SafeInt<SIZE_T>(FileSize2.operator long long());
D3D12VertexShader.pShaderBytecode = malloc(D3D12VertexShader.BytecodeLength);
VertexShader.read(reinterpret_cast<char*>(const_cast<void*>(D3D12VertexShader.pShaderBytecode)), msl::utilities::SafeInt<long long>(D3D12VertexShader.BytecodeLength));
ID3D12PipelineState* D3D12PipelineStateObject = nullptr;
static const D3D12_INPUT_ELEMENT_DESC s_inputElementDesc[2] =
{
{ "SV_Position", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 16, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA , 0 }
};
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = { &s_inputElementDesc[0], _countof(s_inputElementDesc)};
psoDesc.pRootSignature = D3D12RootSignature;
psoDesc.PS = D3D12PixelShader;
psoDesc.VS = D3D12VertexShader;
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
psoDesc.DSVFormat = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
psoDesc.SampleDesc.Count = 1;
ReturnCode = D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&D3D12PipelineStateObject));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12PipelineStateObject->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Pipeline State");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ID3D12CommandQueue* D3D12CommandQueue = nullptr;
D3D12_COMMAND_QUEUE_DESC Desc = {};
Desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
Desc.NodeMask = 0;
Desc.Priority = 0;
Desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ReturnCode = D3D12Device->CreateCommandQueue(&Desc, IID_PPV_ARGS(&D3D12CommandQueue));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12CommandQueue->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Commands::Queue");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ID3D12GraphicsCommandList6* D3D12CommandList = nullptr;
ID3D12CommandAllocator* D3D12CommandAllocator = nullptr;
ReturnCode = D3D12Device->CreateCommandAllocator(_Type, IID_PPV_ARGS(&D3D12CommandAllocator));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12CommandAllocator->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Commands::Allocator");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12CommandAllocator, D3D12PipelineStateObject, IID_PPV_ARGS(&D3D12CommandList));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12CommandList->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Commands::List");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12CommandList->Close();
if (ReturnCode != S_OK)
{
return ReturnCode;
}
IDXGISwapChain4* DXGISwapChain = nullptr;
ID3D12DescriptorHeap* D3D12SwapChainDescriptorHeap = nullptr;
std::vector<ID3D12Resource2*> D3D12SwapChainBuffers = { nullptr, nullptr };
WNDCLASSEXW WndClass = {};
WndClass.cbSize = sizeof(WNDCLASSEXW);
WndClass.hIcon = nullptr;
WndClass.hIconSm = nullptr;
WndClass.hCursor = LoadCursorW(nullptr, IDC_ARROW);
WndClass.hInstance = GetModuleHandleW(nullptr);
WndClass.lpfnWndProc = WindowProc;
WndClass.lpszClassName = g_WndClassName.c_str();
WndClass.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
if (!RegisterClassExW(&WndClass))
{
return -1;
}
HWND m_GameWindow = CreateWindowExW(0, g_WndClassName.c_str(), L"Robo_Lab", WS_OVERLAPPED, 0, 0, 500, 500, nullptr, nullptr, GetModuleHandleW(nullptr), nullptr);
SetWindowPos(m_GameWindow, HWND_TOP, 0, 0, 1920, 1080, SWP_SHOWWINDOW);
DXGI_SWAP_CHAIN_DESC SwapChainDesc = {};
SwapChainDesc.BufferCount = 2;
SwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
SwapChainDesc.BufferDesc.Height = 1080;
SwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
SwapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
SwapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_STRETCHED;
SwapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
SwapChainDesc.BufferDesc.Width = 1920;
SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDesc.OutputWindow = m_GameWindow;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
SwapChainDesc.Windowed = true;
ReturnCode = DXGIFactory->CreateSwapChain(D3D12CommandQueue, &SwapChainDesc, reinterpret_cast<IDXGISwapChain**>(&DXGISwapChain));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
D3D12_DESCRIPTOR_HEAP_DESC DescriptorHeapDesc = {};
DescriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
DescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
DescriptorHeapDesc.NumDescriptors = 2;
ReturnCode = D3D12Device->CreateDescriptorHeap(&DescriptorHeapDesc, IID_PPV_ARGS(&D3D12SwapChainDescriptorHeap));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
uint32_t RTVDescriptorSize = D3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
CD3DX12_CPU_DESCRIPTOR_HANDLE RTVDescriptorHandle(&D3D12SwapChainDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
for (size_t i = 0; i < 2; ++i)
{
DXGISwapChain->GetBuffer(i, IID_PPV_ARGS(&D3D12SwapChainBuffers.at(i)));
wchar_t BufferName[64] = { 0 };
swprintf_s(BufferName, L"SCP-Site Breach::Engine::Direct-X 12::Swap Chain Buffer[%i]", i);
ReturnCode = D3D12SwapChainBuffers.at(i)->SetName(BufferName);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
D3D12Device->CreateRenderTargetView(D3D12SwapChainBuffers.at(i), nullptr, RTVDescriptorHandle);
RTVDescriptorHandle.Offset(1, RTVDescriptorSize);
}
MSG WndMessage = { nullptr };
IsRunning = true;
D3D12_RESOURCE_BARRIER BackBufferResourceBarrier = {};
BackBufferResourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
BackBufferResourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
BackBufferResourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(D3D12DSDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
while (IsRunning)
{
if (PeekMessageW(&WndMessage, m_GameWindow, 0, 0, PM_REMOVE))
{
TranslateMessage(&WndMessage);
DispatchMessageW(&WndMessage);
}
if (GetWindow(m_GameWindow, 0))
{
if (D3D12Fence->GetCompletedValue() < FenceValue)
{
D3D12Fence->SetEventOnCompletion(FenceValue, FenceEvent);
WaitForSingleObject(FenceEvent, INFINITE);
}
CommandList.GetCommandAllocator()->Reset();
D3D12CommandList->Reset(CommandList.GetCommandAllocator(), Pipeline.GetPipeline());
FenceValue++;
BackBufferResourceBarrier.Transition.pResource = D3D12SwapChainBuffers.at(DXGISwapChain->GetCurrentBackBufferIndex());
BackBufferResourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
BackBufferResourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
D3D12CommandList->ResourceBarrier(1, &BackBufferResourceBarrier);
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(D3D12SwapChainDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12SwapChainBuffers.at(DXGISwapChain->GetCurrentBackBufferIndex()), D3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
D3D12CommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
D3D12CommandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
D3D12CommandList->ClearDepthStencilView(D3D12DSDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
D3D12CommandList->SetGraphicsRootSignature(D3D12CommandQueue);
BackBufferResourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
BackBufferResourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
D3D12CommandList->ResourceBarrier(1, &BackBufferResourceBarrier);
D3D12CommandList->Close();
D3D12CommandQueue->ExecuteCommandLists(1, reinterpret_cast<ID3D12CommandList**>(&D3D12CommandList));
D3D12CommandQueue->Signal(D3D12Fence, FenceValue);
DXGISwapChain->Present(0, 0);
}
}
DXGISwapChain->SetFullscreenState(FALSE, nullptr);
DXGISwapChain->Release();
D3D12SwapChainDescriptorHeap->Release();
D3D12SwapChainBuffers.at(0)->Release();
D3D12SwapChainBuffers.at(1)->Release();
D3D12CommandList->Release();
D3D12CommandAllocator->Release()
D3D12CommandQueue->Release();
D3D12PipelineStateObject->Release();
D3D12CommandQueue->Release();
CloseHandle(FenceEvent);
D3D12Fence->Release();
D3D12DSDescriptorHeap->Release();
D3D12DS->Release();
D3D12Device->Release();
#ifdef _SCPDebug
D3D12DeviceDebugInfoQueue->Release();
#endif
DXGIAdapter->Release();
DXGIFactory->Release();
D3D12DebugInterface->Release();
DXGIDebugInfoQueue->Release();
return 0;
}
Note: I converted this code from it's orginal format to this on keeping all of the settings and code. If something got messed up in the procress or converting it, it was a convertion error because this code worked fine except for the fact it was using both of my GPUs.
Edit:
I forgot to mention which GPUs it was using. I have two GPUs. One is a GTX 1650, which is the one I want to use for all of my games, then I have a Intel UHD Graphics 630 (which is the GPU it wants to use) and it's my display driver. When I get the adapter and I get the description, it says it chooses my GTX, but when I look at task manager, it says it's using my display driver's 3D, and my GTX's 3D and copy. Does it have to do when I use "IDXGISwapChain::Present"?
You might have misunderstood what the 3D queue of your integrated GPU is doing.
It's not doing the rendering work, but it is handling the entire desktop composition workload. Which GPU that happens on is determined by where your monitor's framebuffer is located on.
The Taskmanager is misleading as far as you are concerned. It shows you which engine on the GPU side is active (and it shows active time only, no load indicator!), but not from which software side queue this workload was submitted. If you take a look with GPUView instead, you will most likely see it's workload submitted by WDM, not by your process. All usage percentages you see are also wrong, as they are not adjusted for dynamic clock speeds. Your iGPU might as well be in low-power-mode and still show an 80% utilization.
Just how much the internal GPU has to work depends on your swapchain configuration. All the windowed modes naturally result in a significantly higher overhead than the full screen modes (that includes borderless full-screen!), which shows in utilization.

IPortableDeviceEventCallback doesn't work properly (strange behaviour)

I want to receive a callback in my application when a photo on a connected mobile phone was shot (WPD_EVENT_OBJECT_ADDED).
I implemented a WPD client and the IPortableDeviceEventCallback like shown in the Windows Dev Center.
Now my problem is that the IPortableDeviceEventCallback::OnEvent() methode get only invoked if I have opened the DCIM/Camera folder on the phone via Windows Explorer and the explorer starts to creating thumbnails for the images. After I did this once, I receive every event from the phone till I dis- and reconnect it. But if I do not, onEvent() never gets called except I disconnect the phone.
Tested with different Android and iOS phones.
Does anyone have an idea whats going on?
DeviceEventsCallback::DeviceEventsCallback(MyPortableDevice* parent) : IPortableDeviceEventCallback(), cRef(1)
{
parentDevice = parent;
}
DeviceEventsCallback::~DeviceEventsCallback()
{
}
HRESULT __stdcall DeviceEventsCallback::QueryInterface(const IID& riid, LPVOID* ppvObj)
{
static const QITAB qitab[] = {
QITABENT(DeviceEventsCallback, IPortableDeviceEventCallback),
{ },
};
return QISearch(this, qitab, riid, ppvObj);
// HRESULT hr = S_OK;
// if (ppvObj == NULL) {
// hr = E_INVALIDARG;
// return hr;
// }
// if ((riid == IID_IUnknown) ||
// (riid == IID_IPortableDeviceEventCallback)) {
// AddRef();
// *ppvObj = this;
// }
// else {
// *ppvObj = NULL;
// hr = E_NOINTERFACE;
// }
// return hr;
}
ULONG __stdcall DeviceEventsCallback::AddRef()
{
InterlockedIncrement((long*) &cRef);
return cRef;
}
ULONG __stdcall DeviceEventsCallback::Release()
{
ULONG refCount = cRef - 1;
long ref = InterlockedDecrement(&cRef);
if (ref == 0) {
delete this;
return 0;
}
return refCount;
}
HRESULT __stdcall DeviceEventsCallback::OnEvent(IPortableDeviceValues* pEventParameters)
{
HRESULT hr = S_OK;
if (pEventParameters == NULL) {
hr = E_POINTER;
return hr;
}
// The pEventParameters collection contains information about the event that was
// fired. We'll at least need the EVENT_ID to figure out which event was fired
// and based on that retrieve additional values from the collection
// Display the event that was fired
GUID EventId;
if (EventId == WPD_EVENT_DEVICE_CAPABILITIES_UPDATED) {
return S_OK;
}
if (hr == S_OK) {
hr = pEventParameters->GetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, &EventId);
}
if (EventId == WPD_EVENT_DEVICE_REMOVED) {
return S_OK;
}
LPWSTR pwszEventId = NULL;
if (hr == S_OK) {
hr = StringFromCLSID(EventId, &pwszEventId);
}
if (pwszEventId != NULL) {
CoTaskMemFree(pwszEventId);
}
// Display the ID of the object that was affected
// We can also obtain WPD_OBJECT_NAME, WPD_OBJECT_PERSISTENT_UNIQUE_ID,
// WPD_OBJECT_PARENT_ID, etc.
LPWSTR pwszObjectId = NULL;
if (hr == S_OK) {
hr = pEventParameters->GetStringValue(WPD_OBJECT_ID, &pwszObjectId);
}
if (parentDevice != nullptr && pwszObjectId != nullptr && EventId == WPD_EVENT_OBJECT_ADDED) {
qDebug() << "invoked method";
QMetaObject::invokeMethod(parentDevice, "onNewFileOnDevice", Qt::DirectConnection, Q_ARG(QString, QString::fromStdWString(pwszObjectId)));
}
if (pwszObjectId != NULL) {
CoTaskMemFree(pwszObjectId);
}
// Note that we intentionally do not call Release on pEventParameters since we
// do not own it
return hr;
}
And in my MTP implementation I register my DeviceEventsCallback() eventNotifier
void MyPortableDevice::registerEventNotification(ComPtr<IPortableDevice> pDevice)
{
HRESULT hr = S_OK;
PWSTR tempEventCookie = nullptr;
if (pwszEventCookie != nullptr || pDevice == nullptr) {
return;
}
eventNotifier = new(std::nothrow) DeviceEventsCallback(this);
if (eventNotifier == nullptr) {
hr = E_OUTOFMEMORY;
}
if (hr == S_OK) {
hr = pDevice->Advise(0, eventNotifier, nullptr, &tempEventCookie);
}
if (hr == S_OK) {
pwszEventCookie = tempEventCookie;
tempEventCookie = nullptr; // relinquish memory to the caller
}
else {
// Free the event registration cookie because some error occurred
CoTaskMemFree(tempEventCookie);
tempEventCookie = nullptr;
}
}
void MyPortableDevice::unregisterEventsNotification(ComPtr<IPortableDevice> pDevice)
{
if (pDevice == nullptr || pwszEventCookie == nullptr) {
return;
}
HRESULT hr = pDevice->Unadvise(pwszEventCookie);
CoTaskMemFree(pwszEventCookie);
pwszEventCookie = nullptr;
}
My open() function looks like this:
bool MyPortableDevice::open(IPortableDevice** ppDevice)
{
retrieveClientInformation(&clientInformation);
IPortableDevice* pDevice = nullptr;
HRESULT hr = CoCreateInstance(CLSID_PortableDeviceFTM, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevice));
if (SUCCEEDED(hr)) {
wchar_t* wID = new wchar_t[ID.length() + 1];
ID.toWCharArray(wID);
wID[ID.length()] = '\0';
hr = pDevice->Open(wID, clientInformation.Get());
if (hr == E_ACCESSDENIED) {
qDebug() << "Failed to Open the device for Read Write access, will open it for Read-only access instead" << hr;
clientInformation->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS, GENERIC_READ);
hr = pDevice->Open(wID, clientInformation.Get());
readOnly = true;
}
if (SUCCEEDED(hr)) {
// The device successfully opened, obtain an instance of the Device into
// ppDevice so the caller can be returned an opened IPortableDevice.
hr = pDevice->QueryInterface(IID_IPortableDevice, (VOID**)ppDevice);
if (FAILED(hr)) {
qDebug() << "Failed to QueryInterface the opened IPortableDevice";
return false;
}
}
if (pDevice != nullptr) {
pDevice->Release();
pDevice = nullptr;
}
delete [] wID;
wID = nullptr;
if (clientInformation != nullptr) {
clientInformation.Reset();
clientInformation = nullptr;
}
return true;
}
else {
qDebug() << "! Failed to CoCreateInstance CLSID_PortableDeviceFTM, hr = 0x%lx\n" << hr;
return false;
}
}

IShellDisptach: Why does FolderItemVerbs::Release() + CoUninitialize() crash?

I'm having a very bizarre problem with the IShellDispatch COM interface, more specifically with the FolderItemVerbs object, that drives me nuts!
Calling FolderItemVerbs::Release() followed by CoUninitialze() will result in crash. It's clearly reproducible, but only happens 1 out of 10 times.
The crash is an "0xC0000005: Access Violation" error. Running the problematic code in a loop 100% reproduces the crash sooner or later :-(
Please see the example program:
static int TestProc(const TCHAR *pcDirectoryName, const TCHAR *pcFileName)
{
int iSuccess = 0;
IShellDispatch *pShellDispatch = NULL;
Folder *pFolder = NULL; FolderItem *pItem = NULL;
FolderItemVerbs *pVerbs = NULL;
HRESULT hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void**)&pShellDispatch);
if(FAILED(hr) || (pShellDispatch == NULL))
{
iSuccess = -3;
return iSuccess;
}
variant_t vaDirectory(pcDirectoryName);
hr = pShellDispatch->NameSpace(vaDirectory, &pFolder);
if(FAILED(hr) || (pFolder == NULL))
{
iSuccess = -4;
pShellDispatch->Release();
return iSuccess;
}
variant_t vaFileName(pcFileName);
hr = pFolder->ParseName(vaFileName, &pItem);
if(FAILED(hr) || (pItem == NULL))
{
iSuccess = -5;
pFolder->Release();
pShellDispatch->Release();
return iSuccess;
}
hr = pItem->Verbs(&pVerbs);
if(FAILED(hr) || (pVerbs == NULL))
{
iSuccess = -6;
pItem->Release();
pFolder->Release();
pShellDispatch->Release();
return iSuccess;
}
/* Here we would do something with the FolderItemVerbs */
pVerbs->Release(); pVerbs = NULL; //If this line is commented out, we don't get a crash, but a massive memory leak!
pItem->Release(); pItem = NULL;
pFolder->Release(); pFolder = NULL;
pShellDispatch->Release(); pShellDispatch = NULL;
iSuccess = 1;
return iSuccess;
}
//-----------------------------------------------------------------------------
static unsigned __stdcall ThreadProc(void* pArguments)
{
HRESULT hr = CoInitialize(NULL);
if((hr == S_OK) || (hr == S_FALSE))
{
threadParam_t *params = (threadParam_t*) pArguments;
params->returnValue = TestProc(params->pcDirectoryName, params->pcFileName);
CoUninitialize();
}
else
{
if(threadParam_t *params = (threadParam_t*) pArguments)
{
params->returnValue = -10;
}
}
return EXIT_SUCCESS;
}
Please download the complete example code is here:
http://pastie.org/private/0xsnajpia9lsmgnlf2afa
Please also note that I unambiguously tracked down to crash to FolderItemVerbs, because if I never create the FolderItemVerbs object, the crash is gone immediately.
Also if I never call "pVerbs->Release()" before CoUninitialize() the crash is gone too, but this will result in a massive memleak, obviously.
Another strange thing is that the crash will NOT happen, if I run the program under the Debugger! But I can run the program, wait for the crash and then let the Debugger handle the crash.
Unfortunately the Stack Trace that I get then doesn't help much:
http://pastie.org/private/cuwunlun2t5dc5lembpw
I don't think I'm doing anything wrong here. I have checked the code over and over again in the last two days. So this all seems to be a bug in FolderItemVerbs!
Has anybody encountered this before and/or can confirm that this is a bug in FolderItemVerbs? Also, is there any workaround for the problem?
Thanks in advance !!!
Thanks everybody!
Here is the "corrected" code which performs explicit message dispatching:
void DispatchPendingMessages(void)
{
const DWORD uiTimeout = GetTickCount() + 10000;
const HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
unsigned int counter = 0;
if(hEvent)
{
for(;;)
{
MSG Message;
while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
const DWORD nWaitResult = MsgWaitForMultipleObjects(1, &hEvent, FALSE, 250, QS_ALLINPUT | QS_ALLPOSTMESSAGE);
if((nWaitResult == WAIT_TIMEOUT) || (nWaitResult == WAIT_FAILED) || (GetTickCount() >= uiTimeout)) break;
}
CloseHandle(hEvent);
}
}
//-----------------------------------------------------------------------------
static int TestProc(const TCHAR *pcDirectoryName, const TCHAR *pcFileName)
{
int iSuccess = 0;
IShellDispatch *pShellDispatch = NULL;
Folder *pFolder = NULL; FolderItem *pItem = NULL;
FolderItemVerbs *pVerbs = NULL;
HRESULT hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void**)&pShellDispatch);
if(FAILED(hr) || (pShellDispatch == NULL))
{
iSuccess = -3;
return iSuccess;
}
variant_t vaDirectory(pcDirectoryName);
hr = pShellDispatch->NameSpace(vaDirectory, &pFolder);
if(FAILED(hr) || (pFolder == NULL))
{
iSuccess = -4;
pShellDispatch->Release();
return iSuccess;
}
variant_t vaFileName(pcFileName);
hr = pFolder->ParseName(vaFileName, &pItem);
if(FAILED(hr) || (pItem == NULL))
{
iSuccess = -5;
pFolder->Release();
pShellDispatch->Release();
return iSuccess;
}
hr = pItem->Verbs(&pVerbs);
if(FAILED(hr) || (pVerbs == NULL))
{
iSuccess = -6;
pItem->Release();
pFolder->Release();
pShellDispatch->Release();
return iSuccess;
}
/* Here we would do something with the FolderItemVerbs */
pVerbs->Release(); pVerbs = NULL;
pItem->Release(); pItem = NULL;
pFolder->Release(); pFolder = NULL;
pShellDispatch->Release(); pShellDispatch = NULL;
iSuccess = 1;
return iSuccess;
}
//-----------------------------------------------------------------------------
static unsigned __stdcall ThreadProc(void* pArguments)
{
HRESULT hr = CoInitialize(NULL);
if((hr == S_OK) || (hr == S_FALSE))
{
threadParam_t *params = (threadParam_t*) pArguments;
params->returnValue = TestProc(params->pcDirectoryName, params->pcFileName);
DispatchPendingMessages(); //This is required before CoUninitialize() to avoid crash with certain Shell Extensions !!!
CoUninitialize();
}
else
{
if(threadParam_t *params = (threadParam_t*) pArguments)
{
params->returnValue = -10;
}
}
return EXIT_SUCCESS;
}
Couldn't reproduce the crash with that code so far :-)

Getting volume change notifications on Vista/7 (C++)

I'm trying to get notifications whenever the master volume changes on Windows Vista/7. This is the code I'm using:
#include <audiopolicy.h>
#include <audioclient.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <windows.h>
#include <shlwapi.h>
#include <iostream>
#include <Tchar.h>
static const GUID AudioSessionVolumeCtx = { 0x2715279f, 0x4139, 0x4ba0, { 0x9c, 0xb1, 0xb3, 0x51, 0xf1, 0xb5, 0x8a, 0x4a } };
template <class T> void SafeRelease(T **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
class CAudioSessionVolume : public IAudioSessionEvents
{
public:
static HRESULT CreateInstance( UINT uNotificationMessage, HWND hwndNotification, CAudioSessionVolume **ppAudioSessionVolume )
{
CAudioSessionVolume *pAudioSessionVolume = new (std::nothrow)
CAudioSessionVolume(uNotificationMessage, hwndNotification);
if (pAudioSessionVolume == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pAudioSessionVolume->Initialize();
if (SUCCEEDED(hr))
{
*ppAudioSessionVolume = pAudioSessionVolume;
}
else
{
pAudioSessionVolume->Release();
}
return hr;
}
// IUnknown methods.
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CAudioSessionVolume, IAudioSessionEvents),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release()
{
LONG cRef = InterlockedDecrement( &m_cRef );
if (cRef == 0)
{
delete this;
}
return cRef;
}
STDMETHODIMP OnSimpleVolumeChanged( float NewVolume, BOOL NewMute, LPCGUID EventContext )
{
MessageBox(NULL, _T("vol changed"), _T("test"), MB_OK);
return S_OK;
}
// The remaining audio session events do not require any action.
STDMETHODIMP OnDisplayNameChanged(LPCWSTR,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnIconPathChanged(LPCWSTR,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnChannelVolumeChanged(DWORD,float[],DWORD,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnGroupingParamChanged(LPCGUID,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnStateChanged(AudioSessionState)
{
return S_OK;
}
STDMETHODIMP OnSessionDisconnected(AudioSessionDisconnectReason)
{
return S_OK;
}
// Other methods
HRESULT EnableNotifications(BOOL bEnable)
{
HRESULT hr = S_OK;
if (bEnable)
{
hr = m_pAudioSession->RegisterAudioSessionNotification(this);
}
else
{
hr = m_pAudioSession->UnregisterAudioSessionNotification(this);
}
return hr;
}
HRESULT SetDisplayName(const WCHAR *wszName)
{
if (m_pAudioSession == NULL)
{
return E_FAIL;
}
else
{
return m_pAudioSession->SetDisplayName(wszName, NULL);
}
}
protected:
CAudioSessionVolume( UINT uNotificationMessage, HWND hwndNotification ) :
m_cRef(1), m_pAudioSession(NULL), m_pSimpleAudioVolume(NULL)
{
}
~CAudioSessionVolume()
{
EnableNotifications(FALSE);
SafeRelease(&m_pAudioSession);
SafeRelease(&m_pSimpleAudioVolume);
}
HRESULT Initialize()
{
HRESULT hr = S_OK;
IMMDeviceEnumerator *pDeviceEnumerator = NULL;
IMMDevice *pDevice = NULL;
IAudioSessionManager *pAudioSessionManager = NULL;
// Get the enumerator for the audio endpoint devices.
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDeviceEnumerator));
if (FAILED(hr))
{
goto done;
}
// Get the default audio endpoint that the SAR will use.
hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole,
&pDevice);
if (FAILED(hr))
{
goto done;
}
// Get the session manager for this device.
hr = pDevice->Activate(__uuidof(IAudioSessionManager),
CLSCTX_INPROC_SERVER, NULL, (void**) &pAudioSessionManager);
if (FAILED(hr))
{
goto done;
}
// Get the audio session.
hr = pAudioSessionManager->GetAudioSessionControl(
&GUID_NULL, // Get the default audio session.
FALSE, // The session is not cross-process.
&m_pAudioSession);
if (FAILED(hr))
{
goto done;
}
hr = pAudioSessionManager->GetSimpleAudioVolume(&GUID_NULL, 0,
&m_pSimpleAudioVolume);
done:
SafeRelease(&pDeviceEnumerator);
SafeRelease(&pDevice);
SafeRelease(&pAudioSessionManager);
return hr;
}
private:
LONG m_cRef;
IAudioSessionControl *m_pAudioSession;
ISimpleAudioVolume *m_pSimpleAudioVolume;
};
int main()
{
CoInitialize(NULL);
CAudioSessionVolume *asv;
CAudioSessionVolume::CreateInstance(0, NULL, &asv);
asv->EnableNotifications(true);
char s;
gets(&s);
}
I was expecting to get a message box saying "vol changed" when the system volume changes, but I never get a message box.
I got most of the code from http://msdn.microsoft.com/en-us/library/dd374921(VS.85).aspx
What am I doing wrong?
EDIT: I do get notifications when changing the volume for my application (thanks #nobugz). But I want notification when changing the master volume. (Listed as "Device" in Win7's Volume Mixers dialog)
EDIT 2: Larry Osterman has a series of blog posts about the volume in Vista/7. This one in particular is interesting: http://blogs.msdn.com/larryosterman/archive/2007/03/22/fun-with-the-endpoint-volume-interfaces-closing-the-loop.aspx I'll try the code out tomorrow to see if I can get what I want. Now it's time for bed.
EDIT 3: This is the complete code from Larry's blog posts up to and including the link posted above. It does what I need and then some. I'll try to trim the features I don't need.
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <Tchar.h>
#include <strsafe.h>
class CVolumeNotification : public IAudioEndpointVolumeCallback
{
LONG m_RefCount;
~CVolumeNotification(void) {};
public:
CVolumeNotification(void) : m_RefCount(1)
{
}
STDMETHODIMP_(ULONG)AddRef() { return InterlockedIncrement(&m_RefCount); }
STDMETHODIMP_(ULONG)Release()
{
LONG ref = InterlockedDecrement(&m_RefCount);
if (ref == 0)
delete this;
return ref;
}
STDMETHODIMP QueryInterface(REFIID IID, void **ReturnValue)
{
if (IID == IID_IUnknown || IID== __uuidof(IAudioEndpointVolumeCallback))
{
*ReturnValue = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
*ReturnValue = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA NotificationData)
{
wchar_t outputString[256];
DWORD written;
COORD writeCoord;
StringCbPrintf(outputString, sizeof(outputString), L"Volume Changed: %f", NotificationData->fMasterVolume);
writeCoord.X = 0;
writeCoord.Y = 3;
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), outputString, (DWORD)wcslen(outputString), writeCoord, &written);
return S_OK;
}
};
struct TimerContext
{
IAudioMeterInformation *_Meter;
};
const int TimerPeriodicityMS = 100;
void CALLBACK TimerMeterCallback(PTP_CALLBACK_INSTANCE CallbackInstance, PVOID Context, PTP_TIMER Timer)
{
TimerContext *timerContext = (TimerContext *)Context;
wchar_t outputString[256];
float peakValue;
DWORD written;
COORD writeCoord;
StringCbCopy(outputString, sizeof(outputString), L"Meter: ");
timerContext->_Meter->GetPeakValue(&peakValue);
for (size_t i = 0 ; i < peakValue*100; i += 1)
{
StringCbCat(outputString, sizeof(outputString), L"*");
}
for (size_t i = (size_t)(peakValue*100) ; i < 100; i += 1)
{
StringCbCat(outputString, sizeof(outputString), L".");
}
writeCoord.X = 0;
writeCoord.Y = 1;
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), outputString, (DWORD)wcslen(outputString), writeCoord, &written);
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
HRESULT hr;
IMMDeviceEnumerator *deviceEnumerator = NULL;;
HANDLE handle;
TP_CALLBACK_ENVIRON callbackEnvironment;
PTP_CLEANUP_GROUP cleanupGroup;
PTP_TIMER timer;
TimerContext context;
InitializeThreadpoolEnvironment(&callbackEnvironment);
cleanupGroup = CreateThreadpoolCleanupGroup();
SetThreadpoolCallbackCleanupGroup(&callbackEnvironment, cleanupGroup, NULL);
timer = CreateThreadpoolTimer(TimerMeterCallback, &context, &callbackEnvironment);
//
// Clear the screen. Code stolen from: http://support.microsoft.com/kb/319257.
//
handle = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD writtenChars = 0;
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
COORD home;
home.X = home.Y = 0;
GetConsoleScreenBufferInfo(handle, &consoleInfo);
FillConsoleOutputCharacter(handle, L' ', consoleInfo.dwSize.X * consoleInfo.dwSize.Y, home, &writtenChars);
SetConsoleCursorPosition(handle, home);
//
// Set the console to raw mode.
//
DWORD oldMode;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &oldMode);
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), oldMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
//
// Instantiate an endpoint volume object.
//
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
deviceEnumerator->Release();
deviceEnumerator = NULL;
IAudioEndpointVolume *endpointVolume = NULL;
hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
CVolumeNotification *volumeNotification = new CVolumeNotification();
hr = endpointVolume->RegisterControlChangeNotify(volumeNotification);
hr = defaultDevice->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&context._Meter);
defaultDevice->Release();
defaultDevice = NULL;
// Set a 100 millisecond timer.
LARGE_INTEGER timerPeriodicityLI;
FILETIME timerPeriodicity;
timerPeriodicityLI.QuadPart = -1*(TimerPeriodicityMS* 10000 );
timerPeriodicity.dwLowDateTime = timerPeriodicityLI.LowPart;
timerPeriodicity.dwHighDateTime = timerPeriodicityLI.HighPart;
SetThreadpoolTimer(timer, &timerPeriodicity, TimerPeriodicityMS, 10);
wchar_t inputChar = '\0';
while (inputChar != '\r')
{
UINT currentStep, stepCount;
DWORD read, written;
COORD writeCoord;
wchar_t outputString[256];
StringCbCopy(outputString, sizeof(outputString), L"Volume: ");
//
// Calculate the cheesy OSD.
//
endpointVolume->GetVolumeStepInfo(&currentStep, &stepCount);
for (size_t i = 0 ; i < stepCount ; i += 1)
{
if (i <= currentStep)
{
StringCbCat(outputString, sizeof(outputString), L"=");
}
else
{
StringCbCat(outputString, sizeof(outputString), L"-");
}
}
writeCoord.X = 0;
writeCoord.Y = 0;
WriteConsoleOutputCharacter(handle, outputString, (DWORD)wcslen(outputString), writeCoord, &written);
ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &inputChar, 1, &read, NULL);
if (inputChar == '+')
{
endpointVolume->VolumeStepUp(NULL);
}
else if (inputChar == '-')
{
endpointVolume->VolumeStepDown(NULL);
}
}
//
// Remove our notification.
//
endpointVolume->UnregisterControlChangeNotify(volumeNotification);
endpointVolume->Release();
volumeNotification->Release();
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), oldMode);
CloseThreadpoolCleanupGroupMembers(cleanupGroup, FALSE, NULL);
CloseThreadpoolCleanupGroup(cleanupGroup);
cleanupGroup = NULL;
DestroyThreadpoolEnvironment(&callbackEnvironment);
context._Meter->Release();
CoUninitialize();
return 0;
}
EDIT 4: This is a stripped down version of Larry's code.
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <iostream>
#include <Tchar.h>
class CVolumeNotification : public IAudioEndpointVolumeCallback
{
LONG m_RefCount;
~CVolumeNotification(void) {};
public:
CVolumeNotification(void) : m_RefCount(1)
{
}
STDMETHODIMP_(ULONG)AddRef() { return InterlockedIncrement(&m_RefCount); }
STDMETHODIMP_(ULONG)Release()
{
LONG ref = InterlockedDecrement(&m_RefCount);
if (ref == 0)
delete this;
return ref;
}
STDMETHODIMP QueryInterface(REFIID IID, void **ReturnValue)
{
if (IID == IID_IUnknown || IID== __uuidof(IAudioEndpointVolumeCallback))
{
*ReturnValue = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
*ReturnValue = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA NotificationData)
{
std::cout << NotificationData->fMasterVolume << _T(" ");
return S_OK;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
HRESULT hr;
IMMDeviceEnumerator *deviceEnumerator = NULL;;
//
// Instantiate an endpoint volume object.
//
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
deviceEnumerator->Release();
deviceEnumerator = NULL;
IAudioEndpointVolume *endpointVolume = NULL;
hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
CVolumeNotification *volumeNotification = new CVolumeNotification();
hr = endpointVolume->RegisterControlChangeNotify(volumeNotification);
defaultDevice->Release();
defaultDevice = NULL;
wchar_t inputChar = '\0';
while (inputChar != '\r')
{
DWORD read;
ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &inputChar, 1, &read, NULL);
}
//
// Remove our notification.
//
endpointVolume->UnregisterControlChangeNotify(volumeNotification);
endpointVolume->Release();
volumeNotification->Release();
CoUninitialize();
return 0;
}
I still haven't looked at the SDK example. I now know how this stuff works well enough to add what I need to my application. Thanks for everyones help!
It works fine when I try it. Be sure to click on the volume control tray icon, click Mixer and modify the volume for your app.
The Windows SDK "OSD" sample is a much simpler example of monitoring the hardware volume than the one I posted on the blog (you don't need all the metering junk in that post).