http://bugs.winehq.org/show_bug.cgi?id=33155
Bug #: 33155 Summary: Broken winmm recording when using an ACM codec Product: Wine Version: 1.3.25 Platform: x86 OS/Version: Linux Status: NEW Severity: normal Priority: P2 Component: winmm&mci AssignedTo: wine-bugs@winehq.org ReportedBy: hoehle@users.sourceforge.net Classification: Unclassified
Extracted from bug #33045, comment #18 wavein recording using the ACM needs rethinking. Currently, it does anything from hanging, crashing or recording broken streams.
- WID_PullACMData looks incomplete. It starts with checking device->acm_hdr as if it could persist from a prior invocation, however it frees it when returning normally. Thus it should remain local to the function, with device->acm_offs. In error situations, the current code may break, because it may see device->acm_hdr.cbDstLength != 0 on entry from a prior acmStreamConvert MMSYSERR_* return.
- WID_PullACMData needs better error handling. If acmStreamConvert returns an error, the IACaptureClient buffer remains locked, causing any subsequent access to error out: recording stalls.
- In WID_PullACMData, the queue->lpNext condition looks bogus in the light of IMA_ADPCM's 256 bytes block size.
- More generally, PullACMData needs a redesign. What to do when srcLengthUsed < packet_frames ?!? I.e. when the mmdevapi packet length does not match the codec's blocksize, e.g. using 10ms packets while IMA_ADPCM likely needs multiples of 256 bytes. - We should not throw away recorded bytes given enough buffers. - mmdevapi does not accept retrieving less than one packet... - mmdevapi does not allow choosing the packet size.
- WID_PullACMData does not yet handle WOM_DONE correctly. The other bug report contains a patch.
http://bugs.winehq.org/show_bug.cgi?id=33155
Jörg Höhle hoehle@users.sourceforge.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |aeikum@codeweavers.com
--- Comment #1 from Jörg Höhle hoehle@users.sourceforge.net 2013-03-09 04:52:54 CST --- Will have to check whether that can be related to issues involving MS sndrec, e.g. bug #26388 and bug #27721
http://bugs.winehq.org/show_bug.cgi?id=33155
Jörg Höhle hoehle@users.sourceforge.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |source
http://bugs.winehq.org/show_bug.cgi?id=33155
--- Comment #2 from Jörg Höhle hoehle@users.sourceforge.net 2013-03-15 19:10:41 CDT --- A solution to this issue does not look pretty. If somebody has a better idea, please tell:
If srcLengthUsed < packet_frames, then we have to deal with these trailing frames.
Calling the ACM again to try and convert them would be pointless, because presumably they are fewer than the codec's blocksize. For instance, with IMA_ADPCM's 256 blocksize, the typical 44100Hz 10ms 441bytes mmdevapi packet would yield a remainder of 185 bytes...
So those bytes need be remembered (=copied) somewhere, for conversion later, after the next packet is received from mmdevapi. When it is received, its data must be joined with (=copied to) the previously remembered bytes, then call acmStreamConvert (on 185+441 bytes, converting 2x256 and yielding a remainder of 114 bytes this time).
As a result, winmm constantly copies audio samples from mmdevapi. That what I called the mmdevapi-Winmm/ACM impedance mismatch in http://www.winehq.org/pipermail/wine-devel/2013-March/099179.html
So with capturing, as well as we faced in the past about mmdevapi rendering, Wine's winmm over mmdevapi is less performant than the pre-mmdevapi <= wine-1.3.24 code.
Perhaps MS' winmm is cheating. They may know that their packet buffers are adjacent (except at the end of the big mmdevapi buffer of course), observe that GetCurrentPadding shows that more than one packet is ready, then simply invoke acmStreamConvert once on all recorded samples instead of the packet-sized chunks.
Likewise cheating would be possible with rendering: DSound's primary buffer could equate mmdevapi's buffer, with DSound:Lock's buffer splitting being based on GetCurrentPadding modulo number of submitted frames modulo mmdevapi buffer size (if they don't use a hidden API that just gives them mmdevapi's write pointer). Past tests with print("%p",IARC_GetBuffer->data) showed that native appears to use one big mmdevapi buffer and one overflow/wrap-around one, much like winealsa/wineoss, unlike winecoreaudio.
Bug #28748, comment #1 is where Andrew Eikum discovered that apps write into DSound's buffer outside of Lock/Unlock pairs. :-( I recently came across a forum post from somebody who did the same with winmm:waveOutWrite, in an attempt to reduce latency by rewriting already submitted frames! (like PulseAudio does with ALSA, I've heard) IIRC, the guy observed that he could achieve 40ms latency with an XP system and 80ms with an winmm->mmdevapi (w7) system, which I take to mean that writing into already submitted headers less than 40-80ms ahead of GetPosition had no audible effect. I'm waiting for the time when we might discover that apps write directly into mmdevapi's buffer, outside Get/ReleaseBuffer pairs :-( But I digress. Luckily these days, many apps seem to use libraries like XA2 that hopefully are well behaved, instead of directly accessing the too-limited mmdevapi that only knows 48000 or 44100Hz, (like ALSA's fixed rate dmix plugin without resampler in front of it, who would use that?).
https://bugs.winehq.org/show_bug.cgi?id=33155
--- Comment #3 from Austin English austinenglish@gmail.com --- This is your friendly reminder that there has been no bug activity for over 700 days. Is this still an issue in current (1.7.36 or newer) wine?
https://bugs.winehq.org/show_bug.cgi?id=33155
joaopa jeremielapuree@yahoo.fr changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |jeremielapuree@yahoo.fr
--- Comment #4 from joaopa jeremielapuree@yahoo.fr --- No news from the reporter since 9 years. No application (so no download...) Can an administrator close this bug as ABANDONED?