How to play audio using Sink Writer from Microsoft Media Foundation - c++

I'm trying to create an audio visualizer using Microsoft Media Foundation. For this I need to intercept the samples and simultaneously play them. Using a Media Session with Topology and a sample-grabber sink seems impractical and over-complicated, hence I'm trying to use a combination of a Sink Reader and Sink Writer for this (see the right half of the image on Overview of the Media Foundation Architecture). Unfortunately, Audio/Video Playback does not really explain how to do this. The book Developing Microsoft Media Foundation Applications contains a source-to-sink loop on page 92, but that still does not really help me.
Creating the Source Reader works fine and I'm reading nonzero samples. Writing them to the Sink Writer (which uses the Streaming Audio Renderer) does not give me any errors, but I don't hear anything. I tried multiple things like selecting other media types and explicitly selecting the rendering device (although I only have one, as it indicated), but to no avail. Note that playing audio using a Media Session works fine, though!
I based my code on this question: Play audio from file to speaker with Media Foundation.
This is my code at this moment:
#include <iostream>
#include <cassert>
#include <mfidl.h>
#include <mfapi.h>
#include <mfreadwrite.h>
#include <Mferror.h>
#pragma comment(lib, "mf")
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#include <winrt/base.h>
#pragma comment(lib, "windowsapp")
void winHr(const HRESULT result) { winrt::check_hresult(result); }
template<class T>
struct ComPtr : winrt::com_ptr<T>
{
auto operator&() noexcept { return this->put(); }
operator T*() noexcept
{
assert(this->get());
return this->get();
}
};
int main() noexcept
{
winHr(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
winHr(MFStartup(MF_VERSION));
{
ComPtr<IMFSourceReader> reader;
winHr(MFCreateSourceReaderFromURL(
LR"(test.wav)",
nullptr, &reader));
constexpr auto inStreamIndex = MF_SOURCE_READER_FIRST_AUDIO_STREAM;
// Select only the audio stream
winHr(reader->SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, false));
winHr(reader->SetStreamSelection(inStreamIndex, true));
ComPtr<IMFMediaSink> mediaSink;
winHr(MFCreateAudioRenderer(nullptr, &mediaSink));
ComPtr<IMFSinkWriter> writer;
{
ComPtr<IMFStreamSink> streamSink;
winHr(mediaSink->GetStreamSinkByIndex(0, &streamSink));
ComPtr<IMFMediaTypeHandler> typeHandler;
winHr(streamSink->GetMediaTypeHandler(&typeHandler));
ComPtr<IMFMediaType> inputType;
winHr(reader->GetCurrentMediaType(inStreamIndex, &inputType));
ComPtr<IMFMediaType> closestSupportedType;
const auto result = typeHandler->IsMediaTypeSupported(inputType, &closestSupportedType);
if (result == MF_E_INVALIDMEDIATYPE)
{
if (!closestSupportedType)
{
std::cerr << "Media type not supported" << std::endl;
winHr(mediaSink->Shutdown());
goto end; //:o
}
winHr(reader->SetCurrentMediaType(inStreamIndex, nullptr, closestSupportedType));
winHr(typeHandler->SetCurrentMediaType(closestSupportedType));
winHr(MFCreateSinkWriterFromMediaSink(mediaSink, nullptr, &writer));
winHr(writer->SetInputMediaType(0, closestSupportedType, nullptr));
}
else {
winHr(result);
winHr(reader->SetCurrentMediaType(inStreamIndex, nullptr, inputType));
winHr(typeHandler->SetCurrentMediaType(inputType));
winHr(MFCreateSinkWriterFromMediaSink(mediaSink, nullptr, &writer));
winHr(writer->SetInputMediaType(0, inputType, nullptr));
}
}
winHr(writer->BeginWriting());
while (true)
{
ComPtr<IMFSample> sample;
DWORD streamFlags;
MFTIME timestamp;
winHr(reader->ReadSample(inStreamIndex, 0, nullptr, &streamFlags, &timestamp, &sample));
if (streamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
winHr(writer->NotifyEndOfSegment(0));
break;
}
if (streamFlags & MF_SOURCE_READERF_STREAMTICK)
winHr(writer->SendStreamTick(0, timestamp));
if (!sample) continue;
winHr(sample->SetSampleTime(timestamp));
winHr(writer->WriteSample(0, sample));
}
winHr(writer->Flush(0));
std::cout << "(Press enter to stop)" << std::endl;
std::cin.get();
winHr(writer->Finalize());
writer.attach(nullptr);
winHr(mediaSink->Shutdown());
}
end:
winHr(MFShutdown());
CoUninitialize();
}
Just to be clear: when I run this it prints (Press enter to stop) and I can hear from the noise (read: distortions from electronic signals) from my headphones that I can deduce that for a short moment an audio port was opened and then closed, but no actual audio is played. How can I get this to work?
Edit 1: I just fixed that if result != MF_E_INVALIDMEDIATYPE I didn't set the media type, but now I often (but not always, for some reason) get MF_E_TOPO_CODEC_NOT_FOUND at the line winHr(writer->SetInputMediaType(0, inputType, nullptr));. Why would this be? (Still no audio is played in any case.)
Edit 2: Apparently it matters when I create the writer, so now I do that only at the last moment, but now I get the "Media type not supported" error. Maybe I need to manually pick some media type but I will look in to this later -- unless someone knows the answer.

I modified your code to work differently in the following manner:
1. Enumerates the Audio Sink output media types, until it finds a supported one.
2. Sets this media type to the Reader in order to force it to use Audio Resampler DSP (this is what IMFMediaTopology does).
Here is the code, it plays back the input wav file properly. Let me know if it works for you.
#include <iostream>
#include <cassert>
#include <mfidl.h>
#include <mfapi.h>
#include <mfreadwrite.h>
#include <Mferror.h>
#pragma comment(lib, "mf")
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#include <winrt/base.h>
#pragma comment(lib, "windowsapp")
void winHr(const HRESULT result) { winrt::check_hresult(result); }
template<class T>
struct ComPtr : winrt::com_ptr<T>
{
auto operator&() noexcept { return this->put(); }
operator T*() noexcept
{
assert(this->get());
return this->get();
}
};
int main() noexcept
{
winHr(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
winHr(MFStartup(MF_VERSION));
{
ComPtr<IMFSourceReader> reader;
winHr(MFCreateSourceReaderFromURL(
LR"(test.wav)",
nullptr, &reader));
constexpr auto inStreamIndex = MF_SOURCE_READER_FIRST_AUDIO_STREAM;
// Select only the audio stream
winHr(reader->SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, false));
winHr(reader->SetStreamSelection(inStreamIndex, true));
ComPtr<IMFMediaSink> mediaSink;
winHr(MFCreateAudioRenderer(nullptr, &mediaSink));
ComPtr<IMFSinkWriter> writer;
{
ComPtr<IMFStreamSink> streamSink;
winHr(mediaSink->GetStreamSinkByIndex(0, &streamSink));
ComPtr<IMFMediaTypeHandler> typeHandler;
winHr(streamSink->GetMediaTypeHandler(&typeHandler));
DWORD dwCount = 0;
ComPtr<IMFMediaType> inputType;
winHr(typeHandler->GetMediaTypeCount(&dwCount));
for (INT i = 0; i < dwCount; i++)
{
inputType.attach(nullptr);
winHr(typeHandler->GetMediaTypeByIndex(i, &inputType));
if (SUCCEEDED(typeHandler->IsMediaTypeSupported(inputType, NULL)))
break;
}
//ComPtr<IMFMediaType> inputType;
//winHr(reader->GetCurrentMediaType(inStreamIndex, &inputType));
winHr(reader->SetCurrentMediaType(inStreamIndex, NULL, inputType));
//ComPtr<IMFMediaType> closestSupportedType;
//const auto result = typeHandler->IsMediaTypeSupported(inputType, &closestSupportedType);
//if (result == MF_E_INVALIDMEDIATYPE)
//{
// if (!closestSupportedType)
// {
// std::cerr << "Media type not supported" << std::endl;
// winHr(mediaSink->Shutdown());
// goto end; //:o
// }
// winHr(reader->SetCurrentMediaType(inStreamIndex, nullptr, closestSupportedType));
// winHr(typeHandler->SetCurrentMediaType(closestSupportedType));
// winHr(MFCreateSinkWriterFromMediaSink(mediaSink, nullptr, &writer));
// winHr(writer->SetInputMediaType(0, closestSupportedType, nullptr));
//}
//else
{
//winHr(result);
//winHr(reader->SetCurrentMediaType(inStreamIndex, nullptr, inputType));
winHr(typeHandler->SetCurrentMediaType(inputType));
winHr(MFCreateSinkWriterFromMediaSink(mediaSink, nullptr, &writer));
winHr(writer->SetInputMediaType(0, inputType, nullptr));
}
}
winHr(writer->BeginWriting());
while (true)
{
ComPtr<IMFSample> sample;
DWORD streamFlags;
MFTIME timestamp;
winHr(reader->ReadSample(inStreamIndex, 0, nullptr, &streamFlags, &timestamp, &sample));
if (streamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
winHr(writer->NotifyEndOfSegment(0));
break;
}
if (streamFlags & MF_SOURCE_READERF_STREAMTICK)
winHr(writer->SendStreamTick(0, timestamp));
if (!sample)
continue;
// SetSampleTime is redundant
//winHr(sample->SetSampleTime(timestamp));
winHr(writer->WriteSample(0, sample));
}
// Flush shouldn't be called!
// winHr(writer->Flush(0));
std::cout << "(Press enter to stop)" << std::endl;
std::cin.get();
winHr(writer->Finalize());
writer.attach(nullptr);
winHr(mediaSink->Shutdown());
}
end:
winHr(MFShutdown());
CoUninitialize();
}

This code works just fine for me with wav files (Win7, default sound card) :
//----------------------------------------------------------------------------------------------
// Main.cpp
//----------------------------------------------------------------------------------------------
#pragma once
#define WIN32_LEAN_AND_MEAN
#define STRICT
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#pragma comment(lib, "mf")
#pragma comment(lib, "mfuuid")
//----------------------------------------------------------------------------------------------
// Microsoft Windows SDK for Windows 7
#include <WinSDKVer.h>
#include <new>
#include <windows.h>
#include <strsafe.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mferror.h>
#include <mfreadwrite.h>
template <class T> inline void SAFE_RELEASE(T*& p){
if(p){
p->Release();
p = NULL;
}
}
#define AUDIO_FILE L"C:\\Project\\Media\\Audio\\test.wav"
HRESULT ProcessAudio(const WCHAR*);
void main(){
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if(SUCCEEDED(hr)){
hr = MFStartup(MF_VERSION, MFSTARTUP_LITE);
if(SUCCEEDED(hr)){
hr = ProcessAudio(AUDIO_FILE);
hr = MFShutdown();
}
CoUninitialize();
}
}
HRESULT ProcessAudio(const WCHAR*){
IMFSourceReader* pSourceReader = NULL;
IMFMediaType* pType = NULL;
DWORD dwMediaTypeIndex = 0;
IMFMediaSink* pAudioSink = NULL;
IMFStreamSink* pStreamSink = NULL;
IMFMediaTypeHandler* pMediaTypeHandler = NULL;
IMFSinkWriter* pSinkWriter = NULL;
HRESULT hr = MFCreateSourceReaderFromURL(AUDIO_FILE, NULL, &pSourceReader);
// Check native media type
if(SUCCEEDED(hr))
hr = pSourceReader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, dwMediaTypeIndex, &pType);
SAFE_RELEASE(pType);
// Get current media type
if(SUCCEEDED(hr))
hr = pSourceReader->GetCurrentMediaType(dwMediaTypeIndex, &pType);
if(SUCCEEDED(hr))
hr = MFCreateAudioRenderer(NULL, &pAudioSink);
if(SUCCEEDED(hr))
hr = pAudioSink->GetStreamSinkByIndex(0, &pStreamSink);
if(SUCCEEDED(hr))
hr = pStreamSink->GetMediaTypeHandler(&pMediaTypeHandler);
if(FAILED(hr = pMediaTypeHandler->IsMediaTypeSupported(pType, NULL))){
SAFE_RELEASE(pType);
// This is a compatible type with my soundcard
// MF_MT_MAJOR_TYPE MFMediaType_Audio
// MF_MT_SUBTYPE MFAudioFormat_PCM
// MF_MT_AUDIO_NUM_CHANNELS 2
// MF_MT_AUDIO_SAMPLES_PER_SECOND 48000
// MF_MT_AUDIO_BLOCK_ALIGNMENT 4
// MF_MT_AUDIO_AVG_BYTES_PER_SECOND 192000
// MF_MT_AUDIO_BITS_PER_SAMPLE 16
// MF_MT_ALL_SAMPLES_INDEPENDENT 1
// MF_MT_AUDIO_PREFER_WAVEFORMATEX 1
hr = MFCreateMediaType(&pType);
if(SUCCEEDED(hr))
hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
if(SUCCEEDED(hr))
hr = pType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
if(SUCCEEDED(hr))
hr = pType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2);
if(SUCCEEDED(hr))
hr = pType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000);
if(SUCCEEDED(hr))
hr = pType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4);
if(SUCCEEDED(hr))
hr = pType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 192000);
if(SUCCEEDED(hr))
hr = pType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16);
if(SUCCEEDED(hr))
hr = pType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
if(SUCCEEDED(hr))
hr = pType->SetUINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, TRUE);
}
if(SUCCEEDED(hr))
hr = pMediaTypeHandler->SetCurrentMediaType(pType);
if(SUCCEEDED(hr))
hr = MFCreateSinkWriterFromMediaSink(pAudioSink, NULL, &pSinkWriter);
if(SUCCEEDED(hr))
hr = pSinkWriter->BeginWriting();
BOOL bProcess = (hr == S_OK ? TRUE : FALSE);
DWORD streamIndex;
DWORD flags;
LONGLONG llTimeStamp;
IMFSample* pSample = NULL;
while(bProcess){
hr = pSourceReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, &streamIndex, &flags, &llTimeStamp, &pSample);
if(SUCCEEDED(hr) && (flags == 0)){
if(pSample){
hr = pSinkWriter->WriteSample(0, pSample);
SAFE_RELEASE(pSample);
}
}
else{
bProcess = FALSE;
}
}
if(pSinkWriter)
pSinkWriter->Finalize();
if(pAudioSink)
pAudioSink->Shutdown();
SAFE_RELEASE(pSample);
SAFE_RELEASE(pSinkWriter);
SAFE_RELEASE(pMediaTypeHandler);
SAFE_RELEASE(pStreamSink);
SAFE_RELEASE(pAudioSink);
SAFE_RELEASE(pType);
SAFE_RELEASE(pSourceReader);
return hr;
}
If you face problem with MF_E_TOPO_CODEC_NOT_FOUND, share your file. Perhaps extra code is needed in this case.
EDIT
Do you have more than one sound card ?
Share your audio file, so we can see what's going on.
My little hack with Sleep(40), is just here to tell you that doing "while(true)" without pausing have no sens (your processor is working too much). Off course 40 should be better decided. 40 is the minimum processing time processor preemption on windows OS. That my choice for this sample code. We can talk about the best way to choose this value. I'm waiting for your suggestion.

Related

MFGetService doesnt get IMFSimpleAudioVolume on first try

I am playing a mp3 file with windows media foundation and try to set the volume but when i try to get IMFSimpleAudioVolume interface it takes a seemingly random amount of tries to do so. I have got 1 through 200ish tries.
I tried using IMFAudioStreamVolume but the results are the same
Here is the main.cpp
#include <iostream>
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <winrt/base.h>
#pragma comment (lib, "Mfplat.lib")
#pragma comment (lib, "Mfuuid.lib")
#pragma comment (lib, "Mf.lib")
#pragma comment (lib, "Winmm.lib")
template <class T>
using comptr = winrt::com_ptr<T>;
void AddBranchToTopology(comptr<IMFTopology> topology, comptr<IMFMediaSource> mediaSource, comptr<IMFPresentationDescriptor> presentationDesc);
int main()
{
MFStartup(MF_VERSION);
HRESULT hr = S_OK;
comptr<IMFMediaSession> mediaSession;
hr = MFCreateMediaSession(NULL, mediaSession.put());
comptr<IMFSourceResolver> sourceResolver;
MFCreateSourceResolver(sourceResolver.put());
comptr<IMFMediaSource> mediaSource;
MF_OBJECT_TYPE objType = MF_OBJECT_INVALID;
{
comptr<IUnknown> unknown;
hr = sourceResolver->CreateObjectFromURL(L"<file path>",
MF_RESOLUTION_MEDIASOURCE, NULL, &objType, unknown.put());
mediaSource = unknown.as<IMFMediaSource>();
unknown.detach();
}
comptr<IMFPresentationDescriptor> presentationDesc;
hr = mediaSource->CreatePresentationDescriptor(presentationDesc.put());
comptr<IMFTopology> topology;
hr = MFCreateTopology(topology.put());
AddBranchToTopology(topology, mediaSource, presentationDesc);
mediaSession->SetTopology(NULL, topology.get());
comptr<IMFSimpleAudioVolume> simpleVolume;
DWORD tries = 0;
while (!simpleVolume)
{
hr = MFGetService(mediaSession.get(), MR_POLICY_VOLUME_SERVICE, IID_PPV_ARGS(simpleVolume.put()));
tries++;
}
std::cout << tries << "\n";
PROPVARIANT var;
PropVariantInit(&var);
var.vt = VT_EMPTY;
mediaSession->Start(&GUID_NULL, &var);
simpleVolume->SetMasterVolume(0.5f);
while (true)
{
if (GetAsyncKeyState(VK_ESCAPE) & 1)
{
break;
}
}
mediaSession->Shutdown();
mediaSource->Shutdown();
MFShutdown();
return 0;
}
void AddBranchToTopology(comptr<IMFTopology> topology, comptr<IMFMediaSource> mediaSource, comptr<IMFPresentationDescriptor> presentationDesc)
{
comptr<IMFStreamDescriptor> streamDesc;
comptr<IMFTopologyNode> sourceNode;
comptr <IMFTopologyNode> outputNode;
comptr<IMFActivate> activate;
BOOL selected = FALSE;
HRESULT hr = S_OK;
hr = presentationDesc->GetStreamDescriptorByIndex(0, &selected, streamDesc.put());
hr = MFCreateAudioRendererActivate(activate.put());
hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, sourceNode.put());
hr = sourceNode->SetUnknown(MF_TOPONODE_SOURCE, mediaSource.get());
hr = sourceNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, presentationDesc.get());
hr = sourceNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, streamDesc.get());
hr = topology->AddNode(sourceNode.get());
hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, outputNode.put());
hr = outputNode->SetObject(activate.get());
hr = outputNode->SetUINT32(MF_TOPONODE_STREAMID, 0);
hr = outputNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
hr = topology->AddNode(outputNode.get());
hr = sourceNode->ConnectOutput(0, outputNode.get(), 0);
activate->ShutdownObject();
}
IMFMediaSession::SetTopology is asynchronous, so you'd want to sync before asking for service.
This method is asynchronous. If the method returns S_OK, the Media Session sends an MESessionTopologySet event when the operation completes.
mediaSession->SetTopology(NULL, topology.get());
// INSERT BEGIN //
// https://learn.microsoft.com/en-us/windows/win32/medfound/mesessiontopologyset
auto const MediaEventGenerator = mediaSession.as<IMFMediaEventGenerator>();
for(; ; )
{
winrt::com_ptr<IMFMediaEvent> MediaEvent;
winrt::check_hresult(MediaEventGenerator->GetEvent(0, MediaEvent.put()));
MediaEventType Type;
winrt::check_hresult(MediaEvent->GetType(&Type));
//std::cout << Type << std::endl;
if(Type == MESessionTopologySet)
break;
}
// INSERT END //
comptr<IMFSimpleAudioVolume> simpleVolume;
This is just for illustration, in real code you would want to subscribe to events and handle asynchronously (see e.g. Media Foundation samples).

How to read from a USB Joystick with C++ and DirectX8 in Visual Studio 2019

I need help in reading data from a specific joystick when it is connected to a PC in which the data read is received by 2019 visual studio c++ pc program. I want it to detect a particular joystick when connected to a PC based on a product ID or something similar, I don't want it just to detect a joystick that's connected. Then, I would obviously like to have it be read from it and display the read data on the console using cout or something similar. Please provide me a complete example as I've looked at many APIs and function prototypes of the DirectX library to use and I'm still very lost. Thanks. Below is what I have so far;
#include <iostream>
using namespace std;
#include <Windows.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
LPDIRECTINPUT8 di;
HRESULT hr;
LPDIRECTINPUTDEVICE8 joystick;
OLECHAR* ap;
DIDEVCAPS capabilities;
BOOL CALLBACK
enumCallback(const DIDEVICEINSTANCE* instance, VOID* context)
{
HRESULT hr;
// Obtain an interface to the enumerated joystick.
hr = di->CreateDevice(instance->guidInstance, &joystick, NULL);
// If it failed, then we can't use this joystick. (Maybe the user unplugged
// it while we were in the middle of enumerating it.)
if (FAILED(hr)) {
return DIENUM_CONTINUE;
}
// Stop enumeration. Note: we're just taking the first joystick we get. You
// could store all the enumerated joysticks and let the user pick.
return DIENUM_STOP;
}
BOOL CALLBACK
enumAxesCallback(const DIDEVICEOBJECTINSTANCE* instance, VOID* context) {
HWND hDlg = (HWND)context;
DIPROPRANGE propRange;
propRange.diph.dwSize = sizeof(DIPROPRANGE);
propRange.diph.dwHeaderSize = sizeof(DIPROPHEADER);
propRange.diph.dwHow = DIPH_BYID;
propRange.diph.dwObj = instance->dwType;
propRange.lMin = -1000;
propRange.lMax = +1000;
if (FAILED(joystick->SetProperty(DIPROP_RANGE, &propRange.diph))) return DIENUM_STOP;
return DIENUM_CONTINUE;
}
HRESULT
poll(DIJOYSTATE2* js) {
HRESULT hr;
if (joystick == NULL) {
return S_OK;
}
hr = joystick->Poll();
if (FAILED(hr)) {
hr = joystick->Acquire();
while (hr == DIERR_INPUTLOST) hr = joystick->Acquire();
if ((hr == DIERR_INVALIDPARAM) || (hr == DIERR_NOTINITIALIZED)) return E_FAIL;
if (hr == DIERR_OTHERAPPHASPRIO) return S_OK;
}
if (FAILED(hr = joystick->GetDeviceState(sizeof(DIJOYSTATE2), js))) return hr;
return S_OK;
}
int main() {
// Create a DirectInput device
if(FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&di, NULL))) return hr;
if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, NULL, DIEDFL_ATTACHEDONLY))) return hr;
// Make sure we got a joystick
if (joystick == NULL){
printf("Joystick not found.\n");
return E_FAIL;
}
if (FAILED(hr = joystick->SetDataFormat(&c_dfDIJoystick2))) return hr;
if (FAILED(hr = joystick->SetCooperativeLevel(NULL, DISCL_EXCLUSIVE | DISCL_FOREGROUND))) return hr;
capabilities.dwSize = sizeof(DIDEVCAPS);
if (FAILED(hr = joystick->GetCapabilities(&capabilities))) return hr;
if (FAILED(hr = joystick->EnumObjects(enumAxesCallback, NULL, DIDFT_AXIS))) return hr;
if (joystick) {
joystick->Unacquire();
}
return 0;
}

Unable to get to get EveryConnectionCollection for Internet Connection Sharing

I am trying to use Microsoft's library in order to add port mapping to my ICS connection but I'm getting the "failed to get EveryConnectionCollection!\r\n" message. I am extremely new to C++ and I'm not sure where to start in order to try and get this working. I think I might need to initialize INetConnection * pNC = NULL; // fill this out for part 2 below but I'm not sure what needs to be filled out.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <objbase.h>
#include <netcon.h>
#include <stdio.h>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
// as in winsock.h
#define NAT_PROTOCOL_TCP 6
HRESULT DeletePortMapping(INetSharingManager* pNSM, UCHAR ucIPProtocol, short usExternalPort)
{
INetConnection* pNC = NULL; // fill this out for part 2 below
INetSharingEveryConnectionCollection* pNSECC = NULL;
HRESULT hr = pNSM->get_EnumEveryConnection(&pNSECC);
if (!pNSECC)
wprintf(L"failed to get EveryConnectionCollection!\r\n");
if (pNC == NULL) {
wprintf(L"failed to find a valid connection!\r\n");
return E_FAIL;
}
INetSharingConfiguration* pNSC = NULL;
hr = pNSM->get_INetSharingConfigurationForINetConnection(pNC, &pNSC);
pNC->Release(); // don't need this anymore
if (!pNSC) {
wprintf(L"can't make INetSharingConfiguration object!\r\n");
return hr;
}
}
int main()
{
CoInitialize(NULL);
// init security to enum RAS connections
CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, EOAC_NONE, NULL);
INetSharingManager* pNSM = NULL;
HRESULT hr = ::CoCreateInstance(__uuidof(NetSharingManager),
NULL,
CLSCTX_ALL,
__uuidof(INetSharingManager),
(void**)&pNSM);
DeletePortMapping(pNSM, NAT_PROTOCOL_TCP, 555);
}

TaskScheduler RegisterTaskDefinition fails with NULL path in Win10

According to this MSDN doc, we may pass NULL for the path argument:
path [in]
The name of the task. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value created by the Task Scheduler service.
I have a code that use this behavior. The code works fine in Win7 and 8.1, but not in my Win10 box (ver 1709 64-bit, build 16299). In Win10, it will return 0x80070005 aka "Access Denied" when path is NULL. If I specify a name like "Foobar", it will work fine.
Test code:
// Link comsuppw.lib and taskschd.lib.
#include <stdio.h>
#include <windows.h>
#include <atlbase.h>
#include <atlstr.h>
#include <shlobj.h>
#include <taskschd.h>
#include <comutil.h>
class AutoHR {
HRESULT hr;
public:
void operator=(HRESULT hr)
{
this->hr = hr;
if (FAILED(hr)) {throw *this;}
}
HRESULT GetHR() const { return hr; }
};
static void TestTaskSched()
{
AutoHR hr;
CComPtr<ITaskService> taskSvc;
CComPtr<ITaskFolder> taskFol;
CComPtr<ITaskDefinition> taskDef;
CComPtr<IActionCollection> taskAC;
CComPtr<IAction> taskAction;
CComPtr<IExecAction> taskEA;
CComPtr<IRegisteredTask> registeredTask;
try {
hr = taskSvc.CoCreateInstance(CLSID_TaskScheduler, nullptr, CLSCTX_ALL);
hr = taskSvc->Connect(CComVariant(),CComVariant(),CComVariant(),CComVariant());
hr = taskSvc->GetFolder(_bstr_t(L""), &taskFol);
hr = taskSvc->NewTask(0, &taskDef);
hr = taskDef->get_Actions(&taskAC);
hr = taskAC->Create(TASK_ACTION_EXEC, &taskAction);
hr = taskAction.QueryInterface<IExecAction>(&taskEA);
hr = taskEA->put_Path(_bstr_t(L"C:\\Windows\\System32\\cmd.exe"));
hr = taskEA->put_Arguments(_bstr_t(L"/k echo Testing"));
// Note that NULL is passed as the first argument.
hr = taskFol->RegisterTaskDefinition(nullptr, taskDef,
TASK_CREATE_OR_UPDATE, CComVariant(), CComVariant(),
TASK_LOGON_NONE, CComVariant(), &registeredTask);
MessageBoxW(nullptr, L"Succeeded!", L"OK", MB_ICONINFORMATION);
}
catch (AutoHR const &autohr) {
WCHAR buf[99] = {0};
wsprintfW(buf, L"HRESULT error 0x%.8X\n", autohr.GetHR());
MessageBoxW(nullptr, buf, nullptr, MB_ICONERROR);
}
}
int main()
{
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
{
TestTaskSched();
CoUninitialize();
}
return 0;
}
Test result:
Questions:
1) Is there a behavior change between Win10 and older Windows? I suspect there is, but I cannot find any doc that mentions it.
2) Any good alternative for this behavior? I hope I don't have to generate GUID by myself for temporary task creation.

Play Audio Stream Using Windows APIs in C++

To play an .mp3 file in Windows using (in this case) DirectShow you only need:
#include <dshow.h>
#include <cstdio>
// For IID_IGraphBuilder, IID_IMediaControl, IID_IMediaEvent
#pragma comment(lib, "strmiids.lib")
const wchar_t* filePath = L"C:/Users/Public/Music/Sample Music/Sleep Away.mp3";
int main()
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
// Initialize the COM library.
HRESULT hr = ::CoInitialize(NULL);
if (FAILED(hr))
{
::printf("ERROR - Could not initialize COM library");
return 0;
}
// Create the filter graph manager and query for interfaces.
hr = ::CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
::printf("ERROR - Could not create the Filter Graph Manager.");
return 0;
}
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// Build the graph.
hr = pGraph->RenderFile(filePath, NULL);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
}
}
// Clean up in reverse order.
pEvent->Release();
pControl->Release();
pGraph->Release();
::CoUninitialize();
}
I can't find a way to have something like this, but to be able to play an .asx instead, like for example: http://listen.radiotunes.com/public5/solopiano.asx
In MSDN I can only find ways to do this in C# making a Forms application and inserting a WindowsMediaPlayer control in a form.
Any ideas?
An .asx file is actually a playlist. See here some information about the format.
.asx is not supported by DirectShow. See here for the supported formats.
You might parse the file, as it is XML, and find the actual URL of the stream, and then play it, or you could use the Windows Media Player SDK. You can see some sample code for WM SDK here.
OK, got it to work with this example taken from here and adding this extra line: hr = spPlayer->put_URL(L"http://listen.radiotunes.com/public5/solopiano.asx");:
#include "atlbase.h"
#include "atlwin.h"
#include "wmp.h"
#include <cstdio>
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
HRESULT hr = S_OK;
CComBSTR bstrVersionInfo; // Contains the version string.
CComPtr<IWMPPlayer> spPlayer; // Smart pointer to IWMPPlayer interface.
hr = spPlayer.CoCreateInstance(__uuidof(WindowsMediaPlayer), 0, CLSCTX_INPROC_SERVER);
if (SUCCEEDED(hr))
{
hr = spPlayer->get_versionInfo(&bstrVersionInfo);
hr = spPlayer->put_URL(L"http://listen.radiotunes.com/public5/solopiano.asx");
}
if (SUCCEEDED(hr))
{
// Show the version in a message box.
COLE2T pStr(bstrVersionInfo);
MessageBox(NULL, (LPCSTR)pStr, _T("Windows Media Player Version"), MB_OK);
}
// Clean up.
spPlayer.Release();
CoUninitialize();
return 0;
}