http://bugs.winehq.org/show_bug.cgi?id=20232
Summary: mciwave breaks on MSDN example Product: Wine Version: 1.1.30 Platform: All OS/Version: All Status: UNCONFIRMED Severity: normal Priority: P2 Component: winmm&mci AssignedTo: wine-bugs@winehq.org ReportedBy: hoehle@users.sourceforge.net
I'm reviewing mciwave and mciseq and found numerous issues. Concurrently, I'm augmenting the MCI testsuite. I've attached my current mciwave work-in-progress tests to give you an early insight into my work.
The tests so far confirm my model of MCI: I view it like an old-fashioned tape deck with buttons, which you can press in any order. Still there's error checking, e.g. you can't resume when stopped. Like a tape deck, you can switch from playing to recording at any time. Oddly, you can combine fast forward and play in one command, but not rewind with play.
The attached tests work fine on (at least one machine with) MS-Windows, but cause Wine to fail and hang in multiple ways. You've been warned!
I'd be pleased if people could run the tests on more instances of MS-Windows.
I plan to strip down this test file until it at least does not hang anymore in Wine. Then only can it be submitted. Concurrently, I can submit patches to the mci* codebase.
Current issues with the mci code in Wine are: - not distinguishing between STOPPING and STOPPED, PLAYING and GOING TO PLAY, etc.; - seriously broken asynchronous execution; - non-error-proof use of InterlockDecrement. It must only be called when waveInAddBuffer and waveOutWrite succeed, as those cause callbacks to happen; - RIFF .wav file not always correctly written; - the mmio is as much as resource as the wave device and must be properly released (mmioAscend, not only when saving); - many items here and there: + bogus 44000Hz frequency; + premature return (in mcicda); + conversion between #bytes and samples; + switching fInput while playing; + copy&paste errors (InterlockedDecrement need be initialised differently when recording and playing)
The major issue is concurrency. There I'm not sure how to proceed and rewrite mciwave (and mciseq and mcicda).
o One model, Erlang-like, which the OSS driver also implements, is one thread per play and exclusively using message passing to receive commands. This would simplify NOTIFY everywhere. It clearly offers the advantage of being closest to the sequential execution model that is easy to reason about. IMHO, it does not play nicely with the pause command (state machine).
o Continue as currently written, but then think twice and even 3-7 times about how to perform locking among the concurrent threads: - Put InterlockIncrement() to more uses? - Put Events to more uses? - Unlike mciavi, there's no CriticalSection in mciwave and mcicda, yet I'm unconvinced that the current synchronisation via volatile dwStatus can suffice. - But then, identifying the critical sections will be tedious and error prone.
o Combinations of both, e.g. one thread per play or record (not unlike the present code), and dealing (correctly) with PAUSE, STOP and RESUME inside it (via e.g. events to restart a paused thread, or indirectly, by relying on the callbacks+events sent when invoking waveOutRestart and waveInStart -- is it legal at all to call those from a different thread)?
o Is there any other concurrency model suitable in Wine?
Regards, Jörg Höhle