I'm working on a personal command-line driven sound application https://github.com/aparks5/synthcastle and I've run into some trouble.
Question: How can I have a control thread communicate to an audio thread without interruption of the audio?
I want to be able to pass commands from the command line to the audio thread and return back to the command line for further sound manipulation.
The problem is, without multithreading, that if I invoke a command such as "loop 4" (to repeat a pattern 4 times), my "loop" command just waits until the loop finishes before returning execution to the user.
I tried another paradigm by creating a control thread and audio thread, where invoking "loop" immediately returns, caching the passed data along with enqueuing a command to lock-free queue.
In main.cxx:
userData.server = server;
std::shared_ptr<MixerStream> stream = std::make_shared<MixerStream>(SAMPLE_RATE, &userData);
std::thread control(controlThread, stream);
// todo: move graphics thread out of audio thread
std::thread audio(audioThread, stream);
audio.detach();
control.join();
However, when I poll the queue from the audio thread, the data is corrupted and doesn't play in its entirety, only the last bit is played.
int MixerStream::paCallbackMethod(const void* inputBuffer, void* outputBuffer,
...
for (size_t sampIdx = 0; sampIdx < framesPerBuffer; sampIdx++)
{
...
output = m_mixer();
output = clip(output);
*out++ = output;
*out++ = output;
writeBuff[sampIdx] = output;
g_buffer[sampIdx] = static_cast<float>(output*1.0);
}
g_ready = true;
while (m_callbackData->commandsToAudioCallback->size_approx()) {
Commands cmd = *(m_callbackData->commandsToAudioCallback->peek());
m_callbackData->commandsToAudioCallback->pop();
switch (cmd) {
case Commands::START_LOOP:
m_bLoop = true;
while (m_loopTimes > 0) {
playPattern(m_pattern, m_bpm);
m_loopTimes--;
}
break;
case Commands::START_RECORDING:
m_callbackData->server->openWrite();
break;
case Commands::STOP_RECORDING:
m_callbackData->server->closeWrite();
break;
}
m_callbackData->commandsFromAudioCallback->enqueue(cmd); // return command to main thread for deletion
}
...
}
It's clear that nothing should be invoked in paCallbackMethod except for the generation of audio.
It's almost as if I need a third thread in between the UI and the audio, but this doesn't make sense to me.
I'm totally new to multithreading so any pointers as to how I can make control appear seamless would be greatly appreciated.
Update: It's not going to be a perfect solution but my conclusion at the end of my question, creating a third thread so UI -> Control -> Audio actually produced the desired result. I can make loops in the UI, the control thread will poll the stream continuously if it's ready to play, and will issue the commands while the UI is ready to accept new commands. I'm just waiting for it to produce glitches when I try continuous control.
I have a dilemma. My GUI-based C++ app requires to implement drag-and-drop functionality. At the same time, I'm converting this Win32 app to UWP to submit to Windows Store. But there's one issue:
To implement drag-and-drop I need to call these two methods:
OleInitialize(NULL);
//...
HRESULT hr = RegisterDragDrop(hMainWnd, pDropTarget);
and to init WinRT stuff to work with Windows Store, I need to call:
HRESULT hr = RoInitialize(RO_INIT_MULTITHREADED);
Unfortunately OleInitialize initialized COM as single-thread apartment and RoInitialize requires multi-threaded model, while RegisterDragDrop cannot function without calling OleInitialize.
Any idea how to resolve it? (apart from moving RoInitialize and all WinRT code into a worker thread, that will complicate things.)
Raymond Chen in his usual condescending way is pretty good at criticizing things but offers no fix to an existing problem. I'm posting this mostly for later self-reference and in case someone else stumbles upon the same issue as well. I just spent several days trying to resolve this bug, so maybe it will save time for someone else.
Problem
First off, this is a native Win32 code (no .NET or C++/CX.) It is C++ with a sprinkle of WRL for easier handling of WinRT/COM stuff.
In my case I have a Win32 GUI app that implements drag-and-drop of files into its main window. So to init it, one needs to do this from the main thread, right when the app starts:
OleInitialize(NULL);
//...
HRESULT hr = RegisterDragDrop(hMainWnd, pDropTarget);
The OleInitialize call above will initialize COM for the main thread to use single-thread apartment, which is required for RegisterDragDrop to succeed. Without it, the drag-and-drop function will not work.
Then, say you decide to convert this Win32 app to UWP using Microsoft's Project Centennial converter for inclusion into Windows 10 store.
When the app is converted and listed in the store under their trial-license scheme, you will employ the following logic to check if the user has a trial or an activated (i.e. purchased) copy of the app. You'll begin it as such:
//Init COM for WinRT
RoInitialize(RO_INIT_MULTITHREADED);
ComPtr<IStoreContextStatics> pStoreContextStatics;
if(SUCCEEDED(RoGetActivationFactory(
HStringReference(L"Windows.Services.Store.StoreContext").Get(),
__uuidof(pStoreContextStatics),
&pStoreContextStatics)) &&
pStoreContextStatics)
{
//Get store context for the app
ComPtr<IStoreContext> pStoreContext;
if(SUCCEEDED(pStoreContextStatics->GetDefault(&pStoreContext)) &&
pStoreContext)
{
//Got store context
//....
}
}
and then if you need to know trial vs. activated status of the app, using this logic, you'd call:
ComPtr<IAsyncOperation<StoreAppLicense*>> p_opAppLic;
if(SUCCEEDED(pStoreContext->GetAppLicenseAsync(p_opAppLic)) &&
p_opAppLic)
{
ComPtr<IAsyncOperationCompletedHandler<StoreAppLicense*>> p_onAppLicCallback =
Callback<Implements<RuntimeClassFlags<ClassicCom>, IAsyncOperationCompletedHandler<StoreAppLicense*>, FtmBase>>(
[](IAsyncOperation<StoreAppLicense*>* pOp, AsyncStatus status)
{
if (status == AsyncStatus::Completed)
{
ComPtr<IStoreAppLicense> pAppLicResult;
if(SUCCEEDED(pOp->GetResults(&pAppLicResult)) &&
pAppLicResult)
{
BYTE nActive = -1;
BYTE nTrial = -1;
pAppLicResult->get_IsActive(&nActive);
pAppLicResult->get_IsTrial(&nTrial);
//Get app's store ID with SKU
HString strStoreId;
pAppLicResult->get_SkuStoreId(strStoreId.GetAddressOf());
if(nActive == 1 &&
nTrial == 0)
{
//Activated, or purchased copy
}
else if(nActive == 1 &&
nTrial == 1)
{
//Trial copy
}
else
{
//Error -- store returned some gibberish
}
}
}
return S_OK;
});
if(SUCCEEDED(p_opAppLic->put_Completed(p_onAppLicCallback.Get())))
{
//Success initiating async call
}
}
So, if you do all this, your UWP-converted app will behave in a very strange way. Here's an example. Say a user purchases a license for the app thru Windows Store. In turn your app logic calls the code above to see if the app is activated, but what you get back is nActive=0 and nTrial=1. Then if you check strStoreId it will be your app store ID but without the SKU. WTF!?
I know, it's really confusing. As an aside, let me explain. When you first list your app in a Windows Store it will be assigned a Store ID. Something like: ABCDEFG12345. Then if you submit any follow-up update(s) to the first version of the same app, they will add a SKU number to it, that will make the whole app ID change to ABCDEFG12345/0010, then ABCDEFG12345/0011 for the next update, and so on.
Well, the WinRT code above would return my app store ID as ABCDEFG12345 without any SKU attached to it. Which was wrong, since it was a third or so update to the first version of the app. And thus any additional attributes for that app store ID were also wrong.
So that was the issue that I was faced with...
Cause
All the headache that I described above was caused by my omission to check the result code returned from the first RoInitialize call. I would be able to catch the problem much faster if I did this:
//Init COM for WinRT
if(FAILED(RoInitialize(RO_INIT_MULTITHREADED)))
{
//WinRT COM initialization failed
//Go scratch your head why....
}
In this case RoInitialize will fail with error code RPC_E_CHANGED_MODE. The documentation for it is as helpful as Windows Help (F1) option:
A previous call to RoInitialize specified the concurrency model for
this thread as multithread apartment (MTA). This could also indicate
that a change from neutral-threaded apartment to single-threaded
apartment has occurred.
What previous call? The only parameter anyone can call it with is RO_INIT_MULTITHREADED.
So I started digging deeper and by the process of elimination found that the OleInitialize call earlier was the reason why RoInitialize failed and caused the cascade of events that I described above.
Thus I was at the point of asking the question here.
Note on the side, that the bug ridden WinRT library (ref1, ref2, ref3, ref4, ref5) gave me no indications of a problem in all the calls following RoInitialize and somewhere internally silently failed to retrieve the app's SKU because of a single-thread apartment COM initialization.
Hack/Workaround
As was suggested by RbMm in the comments above, doing the following will work, but is a totally undocumented behavior:
if(SUCCEEDED(OleInitialize(0))
{
CoUninitialize();
}
CoInitializeEx(NULL, COINIT_MULTITHREADED);
So if you don't want your app to start crashing for no apparent reason, I would not use it.
Solution
My solution that I went with was to move all the WinRT COM stuff (code I listed above: 2nd and 3rd code segments) into a separate worker thread. It will work fine from there. The issue is marshalling calls between your main thread and this worker thread. It is doable, but requires some work, i.e. using mutexes and events for synchronized access, etc.
So if anyone finds an easier fix for this, please post your solution. I'll mark it as the answer.
solution to the IDsObjPicker crashes I mentioned in the comment ealier, quick code I wrote just now.
Use code below as:
TDsObjPicker lv_PickInfo;
memset(&lv_PickInfo, 0, sizeof(TDsObjPicker));
Sec_InitDsObjPicker(&lv_PickInfo, &lv_InitInfo);
Sec_InvokeDsObjPicker(&lv_PickInfo, 0, &lv_oData);
Solution is to run the dialog in another thread and init the thread without the Ole+Com combination:
// command codes
#define DSOPCMD_EXITTHREAD 1
#define DSOPCMD_INITIALIZE 2
#define DSOPCMD_INVOKE 3
// parameters of object picker via thread
typedef struct tagDsObjPicker
{
// thread handle
HANDLE hThread;
// events
HANDLE hCmdEvt;
HANDLE hRdyEvt;
// commands
UINT CmdCode;
HRESULT hResult;
// command parameters - DSOPCMD_INITIALIZE
DSOP_INIT_INFO *InitInfo;
// command parameters - DSOPCMD_INVOKE
HWND hWnd;
IDataObject **oData;
//
} TDsObjPicker;
DWORD CALLBACK _Sec_DsObjPickerThread(VOID *in_Param)
{
/* locals */
HRESULT lv_hCreateResult;
HRESULT lv_hResult;
TDsObjPicker *lv_PickInfo;
IDsObjectPicker *lv_oPicker;
// get info structure
lv_PickInfo = (TDsObjPicker*)in_Param;
// init COM
CoInitializeEx(NULL, COINIT_MULTITHREADED);
// preclear object pointer
lv_oPicker = NULL;
// create instance of picker
lv_hCreateResult = CoCreateInstance(
CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker, (VOID**)&lv_oPicker);
// while thread is not aborted
while (lv_PickInfo->CmdCode != DSOPCMD_EXITTHREAD)
{
// wait for command event
if (WaitForSingleObject(lv_PickInfo->hCmdEvt, INFINITE) == 0)
{
// what command?
switch (lv_PickInfo->CmdCode)
{
// call init
case DSOPCMD_INITIALIZE:
{
// call object
if (lv_hCreateResult)
lv_hResult = lv_hCreateResult;
else
lv_hResult = lv_oPicker->Initialize(lv_PickInfo->InitInfo);
// done
break;
}
// call invoke
case DSOPCMD_INVOKE:
{
// call object
if (lv_hCreateResult)
lv_hResult = lv_hCreateResult;
else
lv_hResult = lv_oPicker->InvokeDialog(lv_PickInfo->hWnd, lv_PickInfo->oData);
// done
break;
}
// other command codes
default:
lv_hResult = E_FAIL;
break;
}
// store result
lv_PickInfo->hResult = lv_hResult;
// notify caller
SetEvent(lv_PickInfo->hRdyEvt);
}
}
// destroy the picker object
if (lv_oPicker)
lv_oPicker->Release();
// cleanup COM
CoUninitialize();
// leave the thread
return 0;
}
VOID Sec_DoneDsObjPicker(TDsObjPicker *in_PickInfo)
{
// is thread created?
if (in_PickInfo->hThread)
{
// set command code
in_PickInfo->CmdCode = DSOPCMD_EXITTHREAD;
// trigger the thread to process the code
SetEvent(in_PickInfo->hCmdEvt);
// wait for thread to finish
WaitForSingleObject(in_PickInfo->hThread, INFINITE);
// close thread handle
CloseHandle(in_PickInfo->hThread);
}
// close event handles
if (in_PickInfo->hCmdEvt) CloseHandle(in_PickInfo->hCmdEvt);
if (in_PickInfo->hRdyEvt) CloseHandle(in_PickInfo->hRdyEvt);
// clear
memset(in_PickInfo, 0, sizeof(TDsObjPicker));
}
HRESULT Sec_InitDsObjPicker(TDsObjPicker *in_PickInfo, DSOP_INIT_INFO *in_InitInfo)
{
/* locals */
DWORD lv_TID;
// thread not yet created?
if (!in_PickInfo->hThread)
{
// create events
in_PickInfo->hCmdEvt = CreateEvent(0,0,0,0);
in_PickInfo->hRdyEvt = CreateEvent(0,0,0,0);
// if ok
if (in_PickInfo->hCmdEvt && in_PickInfo->hRdyEvt)
{
// create the thread
in_PickInfo->hThread = CreateThread(
0, 0, _Sec_DsObjPickerThread, in_PickInfo, 0, &lv_TID);
}
// failed?
if (!in_PickInfo->hThread)
{
// cleanup
Sec_DoneDsObjPicker(in_PickInfo);
// return with error
return E_OUTOFMEMORY;
}
}
// store parameter
in_PickInfo->InitInfo = in_InitInfo;
// set command code
in_PickInfo->CmdCode = DSOPCMD_INITIALIZE;
// trigger the thread to process the code
SetEvent(in_PickInfo->hCmdEvt);
// wait for result
WaitForSingleObject(in_PickInfo->hRdyEvt, INFINITE);
// return the result
return in_PickInfo->hResult;
}
HRESULT Sec_InvokeDsObjPicker(TDsObjPicker *in_PickInfo, HWND in_hWnd, IDataObject **out_oData)
{
/* locals */
MSG lv_Msg;
// thread not yet created?
if (!in_PickInfo->hThread)
return E_FAIL;
// store parameters
in_PickInfo->hWnd = in_hWnd;
in_PickInfo->oData = out_oData;
// set command
in_PickInfo->CmdCode = DSOPCMD_INVOKE;
// trigger the thread
SetEvent(in_PickInfo->hCmdEvt);
// process messages of this thread while picker runs in other thread until event
while (MsgWaitForMultipleObjects(1, &in_PickInfo->hRdyEvt, 0, INFINITE, QS_ALLINPUT) != 0)
{
// get next message
while (PeekMessage(&lv_Msg, 0,0,0, PM_REMOVE))
{
// translate/dispatch the message
TranslateMessage(&lv_Msg);
DispatchMessage(&lv_Msg);
}
}
// return the result
return in_PickInfo->hResult;
}
You asked why calling OleInitialize() first, followed by CoUnintialize and then reinit COM via CoInitializeEx works and is safe, look at the code of the rewritten OLE server in WINE, https://github.com/wine-mirror/wine/blob/master/dlls/ole32/ole2.c it comes pretty close to the "real thing". The OleInitialize calls CoInitializeEx itself with COINIT_APARTMENTTHREADED and fails before doing the OLE-specific initializations upon a fail of CoInitializeEx. There is no reason to fail as the OLE code can run as well in MULTITHREADED mode. Remember MULTITHREADED means the caller must take care of synchronisation/locking while with APARTMENTTHREADED the COM libray will handle it for the code. So if you make sure you do not call the OLE code like dragdrop and clipboard at the same time from multiple threads then there is no problem. Keeping all UI in the main thread will do that. As you should already write multithreaded-aware code yourself using the requested MULTITHREADED mode.
I have the problem with directshow filters/drivers which lock the process when COM is initialized with APARTMENTTHREADED even when directshow is called from a thread with THREADED while the main UI thread runs in APARTMENTTHREADED.
Uninitializing COM after initializing OLE, then re-inititializing COM with MULTITHREAED during startup in the main UI thread makes you bypass the failure in OleInitialize. It is the best solution to make sure all runs well.
Every time I save a certain script file I'm working on in NotePad++, I am required to upload the changes to our server so that we can deploy the changes to various machines.
I sometimes forget to upload the changes after refactoring my code in NotePad++ and I was wondering if there was a way for me to create a simple application that would listen for a 'Save' event and automatically upload the file for me.
I am currently running on a Windows OS and was hoping to do this using C++. I'd like to explore Windows Events and possibly tie into an event hook to accomplish this. Any other languages would be welcome as well.
Any ideas or tips?
Here is my code thus far following Josh's recommendations below:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
void RefreshDirectory(LPTSTR);
void WatchDirectory(LPTSTR);
void _tmain(int argc, TCHAR *argv[])
{
if (argc != 2)
{
_tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);
return;
}
WatchDirectory(argv[1]);
}
void WatchDirectory(LPTSTR lpDir)
{
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];
TCHAR lpDrive[4];
TCHAR lpFile[_MAX_FNAME];
TCHAR lpExt[_MAX_EXT];
_tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);
lpDrive[2] = (TCHAR)'\\';
lpDrive[3] = (TCHAR)'\0';
// Watch the directory for file creation and deletion.
dwChangeHandles[0] = FindFirstChangeNotification(
lpDir, // directory to watch
FALSE, // do not watch subtree
FILE_NOTIFY_CHANGE_LAST_WRITE); // watch file name changes
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
{
printf("\n ERROR: FindFirstChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
// Make a final validation check on our handles.
if ((dwChangeHandles[0] == NULL))
{
printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
ExitProcess(GetLastError());
}
// Change notification is set. Now wait on both notification
// handles and refresh accordingly.
while (TRUE)
{
// Wait for notification.
printf("\nWaiting for notification...\n");
// Waits until the specified object is in the signaled state or
// the time-out interval elapses.
// Because our second parameter is set to INFINITE, the function will
// return only when the object is signaled.
dwWaitStatus = WaitForSingleObject(dwChangeHandles, INFINITE);
switch (dwWaitStatus)
{
// Our return value, WAIT_OBJECT_0 signifies that the first object
// signaled the event.
case WAIT_OBJECT_0:
// A file was created, renamed, or deleted in the directory.
// Refresh this directory and restart the notification.
RefreshDirectory(lpDir);
if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE)
{
printf("\n ERROR: FindNextChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
break;
case WAIT_TIMEOUT:
// A timeout occurred, this would happen if some value other
// than INFINITE is used in the Wait call and no changes occur.
// In a single-threaded environment you might not want an
// INFINITE wait.
printf("\nNo changes in the timeout period.\n");
break;
default:
printf("\n ERROR: Unhandled dwWaitStatus.\n");
ExitProcess(GetLastError());
break;
}
}
}
void RefreshDirectory(LPTSTR lpDir)
{
// This is where you might place code to refresh your
// directory listing, but not the subtree because it
// would not be necessary.
_tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
}
You can monitor the filesystem for changes using FindFirstChangeNotification. When you call this function, you get a HANDLE back. You can wait on that handle using WaitSingleObject (or similar). When the wait returns, you can use ReadDirectoryChanges to figure out exactly what happened. If whatever happens matches some event or change you care about for your file, you can take the appropriate action... otherwise ignore the event.
Because you'll be waiting (and thus blocking the thread), you may want to perform this work on a worker thread if you want your program in question to be doing anything else.
A simple way to start might be to listen for events with the FILE_NOTIFY_CHANGE_LAST_WRITE filter; this will release your wait when files in the monitored directory are written to.
Note that not all programs save files in the same way; some open the existing file and write to it, others delete it and replace, or some combination thereof (first writing to a temporary file, then swapping it with the original). Consequently it may not be as straightforward as waiting for just last-write notifications to accomplish precisely what you're after.
Think about writing a NP++ plugin instead.
You can register your plugin to be notified whenever a file is saved or about to be saved using NPPN_FILESAVED or NPPN_FILEBEFORESAVE.
Please look at this link:
http://docs.notepad-plus-plus.org/index.php/Messages_And_Notifications
I am writing windows device driver first time for multiport serial pci card.May be this one is stupid question but i got stuck.Need someone's help.Let me first explain what I have done yet.I have bus driver which creates number of child (2/4/8/16) depends on card. Now I have to write function driver for it.The bus driver creates interrupt which I have to use.Now in my driver I got bus interface,interrupt created in bus driver and related information.I am using Serial Port Driver Sample for reference.Now in SerialISR () routine my driver got stuck in while loop.
ServicedAnInterrupt = TRUE;
do {
InterruptIdReg &= (~SERIAL_IIR_FIFOS_ENABLED);
switch (InterruptIdReg) {
case SERIAL_IIR_RLS: {
READ_LINE_STATUS(Extension, Extension->Controller);
break;
}
case SERIAL_IIR_RDA:
case SERIAL_IIR_CTI: {
READ_RECEIVE_BUFFER(Extension, Extension->Controller);
break;
}
case SERIAL_IIR_THR: {
//
// Alread clear from reading the iir.
//
// We want to keep close track of whether
// the holding register is empty.
//
Extension->HoldingEmpty = TRUE;
break;
}
case SERIAL_IIR_MS: {
READ_MODEM_STATUS(Extension, Extension->Controller);
break;
}
default: {
ASSERT(FALSE);
break;
}
}
} while (!((InterruptIdReg =
READ_INTERRUPT_ID_REG(Extension, Extension->Controller))
& SERIAL_IIR_NO_INTERRUPT_PENDING));
Every time it goes into case SERIAL_IIR_MS. This process continue for some time about 1 min & then test pc will crash.What can be the reason behind that & what should I do to overcome this problem?I have gone through msdn library information. Also read issues regarding this on OSR website.
I am playing a video to get some screens using DirectShow.
I am doing this in a loop by calling IMediaControl->Run, IVMRWindowlessControl->GetCurrentImage and then a IMediaSeeking->SetPositions.
The problem is that I cannot detect when the video is over. IMediaSeeking->SetPositions returns always same value (S_FALSE). IMediaControl->Runalso returns always S_FALSE. I have also tried IMediaEvent->GetEvent after the call to IMediaControl->Run to check for EC_COMPLETE but instead returns (always) EC_CLOCK_CHANGED.
How can I detect the end of video ? Thanks
UPDATE: Doing something like
long eventCode = 0;
LONG_PTR ptrParam1 = 0;
LONG_PTR ptrParam2 = 0;
long timeoutMs = INFINITE;
while (SUCCEEDED(pEvent->GetEvent(&eventCode, &ptrParam1, &ptrParam1, timeoutMs)))
{
if (eventCode == EC_COMPLETE)
{
break;
}
// Free the event data.
hr = pEvent->FreeEventParams(eventCode, ptrParam1, ptrParam1);
if (FAILED(hr))
{
break;
}
}
blocks after few events: 0x53 (EC_VMR_RENDERDEVICE_SET), 0x0D (EC_CLOCK_CHANGED), 0x0E (EC_PAUSED), next call to GetEvent is blocking and the video is rendered (played frame by frame) in my IVideoWindow
You should be doing IMediaEvent->GetEvent, however note you will be receiving various events, not only EC_CLOCK_CHANGED. Keep receiving and you are to get EC_COMPLETE. Step 6: Handle Graph Events on MSDN explains this in detail.
Check the state of the filter graph with IMediaControl::GetState and see if it is stopped. You can also get the duration of the video from IMediaSeeking::GetDuration that you may find helpful.
Another option is to use event signaling. This event processing can be off-threaded.