views:

850

answers:

4

Hi

I cannot find any information about the thread-safety of the waveOut API.

After i creating new waveOut handle, i have those threads:

Thread 1: Buffers handling. Uses those API functions:

  • waveOutPrepareHeader
  • waveOutWrite
  • waveOutUnprepareHeader

Thread 2: Gui, Controller thread. Uses those API functions:

  • waveOutPause
  • waveOutRestart
  • waveOutReset
  • waveOutBreakLoop

Those two threads are running while using concurrently the same waveOut handle. In my tests, i didn't saw any problem with the functionality, but it doesn't mean that it safe.

Is this architecture thread-safe? Is there any documentation about the thread safety of the waveOut API? Any other suggestions about the waveOut API thread-safety?

thanks.

+2  A: 

I didn't see any documentation either, but I can't imagine that a call to waveOutWrite would be considered safe to be run concurrently with a call to WaveOutRestart on the same handle.

If you're using VS2010 Beta2 I would look at the various walkthroughs for the Agents Library and attempt to turn this into a producer consumer problem where you are passing messages like write,pause,restart, etc.

If you aren't using Visual Studio 2010 (or can't) I would encourage you to find a way to break this into a producer consumer problem using threads and some sort of internally synchronized queue that stores the commands to process. If the messages aren't that frequent and given that you only have 2 threads working on this queue, you may be able to get away with puting a plain old Win32 critical section around a std::queue...

hope this helps.

Rick
+2  A: 

In general the waveOut API should be thread-safe. Because usually a waveOutOpen() creates its own thread, and all waveOut* functions send messages to that thread. But I can not give you a proof...

However, you can change your application to make it safe in any case:

  1. start your thread for buffer management, remember dwBufferThreadId
  2. from GUI thread call waveOutOpen with dwCallback set to dwBufferThreadId and fdwOpen to CALLBACK_THREAD
  3. your buffer management thread: "waveOutWrite" some buffers in advance, the loop on GetMessage()
  4. waveOutOpen will send a WOM_DONE whenever a buffer is finished and a new buffer is required, this is the moment to waveOutWrite a new buffer from within that thread
  5. make your calls to waveOutPause, waveOutRestart and so on from GUI thread (nothing in MSDN speaks against it, and all examples do this, even if the buffers will be filled from another thread)

example 1

If you want to be 100% sure, you could just grab a windows message (WM_USER+0), and call PostThreadMessage( WM_USER+0, dwBufferThreadId, MY_CTL_PAUSE,0 ) and then upon receiving that message in your buffering thread, you call waveOutPause() there. Windows message queues save you some work on writing your own message queues ;-)

frunsi
+1  A: 

It may be thread safe, but if you (or I) can't find any official documentation stating it is thread safe then assume it isn't and add your own thread synchronization. A light weight EnterCriticalSection / LeaveCriticalSection implementation is probably no more than a dozen lines of code.

No amount of testing can ever assure you that the API is thread safe: problems may only occur on some architectures with some CPU or bus speeds or with some sound cards. Neither you (nor Microsoft) has the ability to test all possible configurations.

You also shouldn't make any assumptions about what Microsoft or Intel or a sound card manufacturer or driver writer will do in some future implementation.

MZB
+1  A: 

Sadly, it's not safe even in a single threaded environment. Look at this question for a discussion:

http://stackoverflow.com/questions/195696/why-would-waveoutwrite-cause-an-exception-in-the-debug-heap

Attempts to report this to Microsoft resulted in them closing the bug. They're not going to fix it.

Ori Pessach