From: KJ Liew <liewkj@yahoo.com>
To: "Zoltán Kővágó" <dirty.ice.hu@gmail.com>
Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>,
"QEMU Developers" <qemu-devel@nongnu.org>,
"Gerd Hoffmann" <kraxel@redhat.com>
Subject: Re: [PATCH] audio/dsound: fix invalid parameters error
Date: Sat, 1 Feb 2020 10:28:14 -0800 [thread overview]
Message-ID: <20200201182814.GA35660@PC-SEANJYE> (raw)
In-Reply-To: <2b889c2c-04ac-c6ef-ae3e-2901492a2824@gmail.com>
On Mon, Jan 27, 2020 at 02:46:58AM +0100, Zoltán Kővágó wrote:
> On 2020-01-18 07:30, Philippe Mathieu-Daudé wrote:
> > On 1/17/20 7:26 PM, KJ Liew wrote:
> > > QEMU Windows has broken dsound backend since the rewrite of audio API in
> > > version 4.2.0. Both playback and capture buffers failed to lock with
> > > invalid parameters error.
> >
> > Fixes: 7fa9754ac88 (dsoundaudio: port to the new audio backend api)
>
> Hmm, I see the old code specified those parameters, but MSDN reads:
>
> If the application passes NULL for the ppvAudioPtr2 and pdwAudioBytes2
> parameters, the lock extends no further than the end of the buffer and does
> not wrap.
>
> Looks like this means that if the lock doesn't fit in the buffer it fails
> instead of truncating it. I'm sure I tested the code under wine, and
> probably in a win8.1 vm too, and it worked there, maybe it's dependent on
> the windows version or sound driver?
>
I was testing on several real Win10 machines. QEMU built with
MSYS2/mingw-w64-x86_64 GNU toolchain.
> >
> > Cc'ing Zoltán who wrote 7fa9754ac88, and Gerd (the maintainer of this
> > file):
> >
> > $ ./scripts/get_maintainer.pl -f audio/dsoundaudio.c
> > Gerd Hoffmann <kraxel@redhat.com> (maintainer:Audio)
> >
> > > --- ../orig/qemu-4.2.0/audio/dsoundaudio.c 2019-12-12
> > > 10:20:47.000000000 -0800
> > > +++ ../qemu-4.2.0/audio/dsoundaudio.c 2020-01-17
> > > 08:05:46.783966900 -0800
> > > @@ -53,6 +53,7 @@
> > > typedef struct {
> > > HWVoiceOut hw;
> > > LPDIRECTSOUNDBUFFER dsound_buffer;
> > > + void *last_buf;
> > > dsound *s;
> > > } DSoundVoiceOut;
> > > @@ -414,10 +415,10 @@
> > > DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
> > > LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
> > > HRESULT hr;
> > > - DWORD ppos, act_size;
> > > + DWORD ppos, act_size, last_size;
> > > size_t req_size;
> > > int err;
> > > - void *ret;
> > > + void *ret, *last_ret;
> > > hr = IDirectSoundBuffer_GetCurrentPosition(dsb, &ppos, NULL);
> > > if (FAILED(hr)) {
> > > @@ -426,17 +427,24 @@
> > > return NULL;
> > > }
> > > + if (ppos == hw->pos_emul) {
> > > + *size = 0;
> > > + return ds->last_buf;
> > > + }
> > > +
> > > req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
> > > req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
> > > - err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size,
> > > &ret, NULL,
> > > - &act_size, NULL, false, ds->s);
> > > + err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size,
> > > &ret, &last_ret,
> > > + &act_size, &last_size, false, ds->s);
> > > if (err) {
> > > dolog("Failed to lock buffer\n");
> > > *size = 0;
> > > return NULL;
> > > }
> > > + ds->last_buf = g_realloc(ds->last_buf, act_size);
> > > + memcpy(ds->last_buf, ret, act_size);
> > > *size = act_size;
> > > return ret;
> > > }
>
> I don't really understand what's happening here, why do you need that memory
> allocation and memcpy? This function should return a buffer where the
> caller will write data, that *size = 0; when returning ds->last_buf also
> looks incorrect to me (the calling function won't write anything into it).
I was trying to fix the invalid parameters errors from
dsound_lock_out()/dsound_lock_in(). I have to say that I wasn't quite sure if the
content of buffer matters to the caller, but an assumption that safe buffer for
read/write got to be there. So I just memcpy to keep the last good
buffer.
The lock seemed to fail for dsound_lock_out()/dsound_lock_in() when
(ppos == hw->pos_emul) for _out and (cpos == hw->pos_emul) for _in.
Hence, the last_buf was returned to the caller. Since the lock did not
take place, the *size = 0 provides the hint to skip the unlock,
otherwise, dsound_unlock_out() failed for buffer that has never been
locked.
> I'm attaching a patch with a probably better (and totally untested) way to
> do this (if someone can tell me how to copy-paste a patch into thunderbird
> without it messing up long lines, please tell me).
I checked out your patch. Unfortunately, it did not
address the invalid paramters errors. The console still flooded with error
messages:
dsound: Could not lock playback buffer
dsound: Reason: An invalid parameter was passed to the returning function
dsound: Failed to lock buffer
> > > @@ -445,6 +453,8 @@
> > > {
> > > DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
> > > LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
> > > + if (len == 0)
> > > + return 0;
> > > int err = dsound_unlock_out(dsb, buf, NULL, len, 0);
> > > if (err) {
>
> Msdn says "The second pointer is needed even if nothing was written to the
> second pointer." so that NULL doesn't look okay.
>
> > > @@ -508,10 +518,10 @@
> > > DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
> > > LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
> > > HRESULT hr;
> > > - DWORD cpos, act_size;
> > > + DWORD cpos, act_size, last_size;
> > > size_t req_size;
> > > int err;
> > > - void *ret;
> > > + void *ret, *last_ret;
> > > hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, &cpos,
> > > NULL);
> > > if (FAILED(hr)) {
> > > @@ -520,11 +530,16 @@
> > > return NULL;
> > > }
> > > + if (cpos == hw->pos_emul) {
> > > + *size = 0;
> > > + return NULL;
> > > + }
> > > +
> > > req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
> > > req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
> > > - err = dsound_lock_in(dscb, &hw->info, hw->pos_emul, req_size,
> > > &ret, NULL,
> > > - &act_size, NULL, false, ds->s);
> > > + err = dsound_lock_in(dscb, &hw->info, hw->pos_emul, req_size,
> > > &ret, &last_ret,
> > > + &act_size, &last_size, false, ds->s);
> > > if (err) {
> > > dolog("Failed to lock buffer\n");
> > > *size = 0;
> > >
>
> You're completely ignoring last_ret and last_size here. Don't you lose
> samples here? I think it's possible to do something like I posted above
> with output here.
>
> Regards,
> Zoltan
> diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
> index c265c0094b..b6bc241faa 100644
> --- a/audio/dsoundaudio.c
> +++ b/audio/dsoundaudio.c
> @@ -53,6 +53,9 @@ typedef struct {
> typedef struct {
> HWVoiceOut hw;
> LPDIRECTSOUNDBUFFER dsound_buffer;
> + void *buffer1, buffer2;
> + DWORD size1, size2;
> + bool has_remaining;
> dsound *s;
> } DSoundVoiceOut;
>
> @@ -414,10 +417,16 @@ static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
> DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
> LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
> HRESULT hr;
> - DWORD ppos, act_size;
> + DWORD ppos, act_size1, act_size2;
> size_t req_size;
> int err;
> - void *ret;
> + void *ret1, *ret2;
> +
> + if (ds->has_remaining) {
> + ds->has_remaining = false;
> + *size = ds->size2;
> + return ds->buffer2;
> + }
>
> hr = IDirectSoundBuffer_GetCurrentPosition(dsb, &ppos, NULL);
> if (FAILED(hr)) {
> @@ -429,15 +438,20 @@ static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
> req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
> req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
>
> - err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
> - &act_size, NULL, false, ds->s);
> + err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret1, &ret2,
> + &act_size1, &act_size2, false, ds->s);
> if (err) {
> dolog("Failed to lock buffer\n");
> *size = 0;
> return NULL;
> }
>
> - *size = act_size;
> + *size = act_size1;
> + ds->buffer1 = ret1;
> + ds->buffer2 = ret2;
> + ds->size1 = act_size1;
> + ds->size2 = act_size2;
> + ds->has_remaining = ret2 != NULL;
> return ret;
> }
>
> @@ -445,7 +459,16 @@ static size_t dsound_put_buffer_out(HWVoiceOut *hw, void *buf, size_t len)
> {
> DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
> LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
> - int err = dsound_unlock_out(dsb, buf, NULL, len, 0);
> + int err;
> +
> + if (ds->has_remaining) {
> + ds->size1 = len;
> + hw->pos_emul = (hw->pos_emul + len) % hw->size_emul;
> + return len;
> + }
> +
> + *(ds->buffer2 ? &ds->size2 : &ds->size1) = len;
> + err = dsound_unlock_out(dsb, ds->buffer1, ds->buffer2, ds->size1, ds->size2);
>
> if (err) {
> dolog("Failed to unlock buffer!!\n");
next prev parent reply other threads:[~2020-02-01 18:29 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20200117182621.GB13724.ref@chuwi-lt0>
2020-01-17 18:26 ` [PATCH] audio/dsound: fix invalid parameters error KJ Liew
2020-01-18 6:30 ` Philippe Mathieu-Daudé
2020-01-27 1:46 ` Zoltán Kővágó
2020-01-31 7:55 ` Gerd Hoffmann
2020-02-01 18:28 ` KJ Liew [this message]
2020-02-02 23:02 Kővágó, Zoltán
2020-02-03 7:56 ` Howard Spoelstra
2020-02-03 9:18 ` Philippe Mathieu-Daudé
2020-02-03 9:25 ` Howard Spoelstra
2020-02-06 13:38 ` Gerd Hoffmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200201182814.GA35660@PC-SEANJYE \
--to=liewkj@yahoo.com \
--cc=dirty.ice.hu@gmail.com \
--cc=kraxel@redhat.com \
--cc=philmd@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).