Am 08.04.25 um 14:55 schrieb Christian Schoenebeck:
> On Friday, April 4, 2025 1:34:27 PM CEST BALATON Zoltan wrote:
>> On Fri, 4 Apr 2025, Christian Schoenebeck wrote:
>>> On Monday, March 31, 2025 3:05:24 PM CEST BALATON Zoltan wrote:
>>>> On Sun, 23 Mar 2025, Christian Schoenebeck wrote:
>>>>> On Sunday, March 16, 2025 1:20:46 AM CET BALATON Zoltan wrote:
>>>>>> Quoting Volker Rümelin: "try-poll=on tells the ALSA backend to try to
>>>>>> use an event loop instead of the audio timer. This works most of the
>>>>>> time. But the poll event handler in the ALSA backend has a bug. For
>>>>>> example, if the guest can't provide enough audio frames in time, the
>>>>>> ALSA buffer is only partly full and the event handler will be called
>>>>>> again and again on every iteration of the main loop. This increases
>>>>>> the processor load and the guest has less processor time to provide
>>>>>> new audio frames in time. I have two examples where a guest can't
>>>>>> recover from this situation and the guest seems to hang."
>>>>>>
>>>>>> One reproducer I've found is booting MorphOS demo iso on
>>>>>> qemu-system-ppc -machine pegasos2 -audio alsa which should play a
>>>>>> startup sound but instead it freezes. Even when it does not hang it
>>>>>> plays choppy sound. Volker suggested using command line to set
>>>>>> try-poll=off saying: "The try-poll=off arguments are typically
>>>>>> necessary, because the alsa backend has a design issue with
>>>>>> try-poll=on. If the guest can't provide enough audio frames, it's
>>>>>> really unhelpful to ask for new audio frames on every main loop
>>>>>> iteration until the guest can provide enough audio frames. Timer based
>>>>>> playback doesn't have that problem."
>>>>>>
>>>>>> But users cannot easily find this option and having a non-working
>>>>>> default is really unhelpful so to make life easier just set it to
>>>>>> false by default which works until the issue with the alsa backend can
>>>>>> be fixed.
>>>>>>
>>>>>> Signed-off-by: BALATON Zoltan <bala...@eik.bme.hu>
>>>>>> ---
>>>>>> This fixes my issue but if somebody has a better fix I'm open to that
>>>>>> too.
>>>>>>
>>>>>>  audio/alsaaudio.c | 2 +-
>>>>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
>>>>>> index cacae1ea59..9b6c01c0ef 100644
>>>>>> --- a/audio/alsaaudio.c
>>>>>> +++ b/audio/alsaaudio.c
>>>>>> @@ -899,7 +899,7 @@ static void alsa_enable_in(HWVoiceIn *hw, bool 
>>>>>> enable)
>>>>>>  static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions 
>>>>>> *apdo)
>>>>>>  {
>>>>>>      if (!apdo->has_try_poll) {
>>>>>> -        apdo->try_poll = true;
>>>>>> +        apdo->try_poll = false;
>>>>>>          apdo->has_try_poll = true;
>>>>>>      }
>>>>>>  }
>>>>>>
>>>>> Correct me if I am wrong, but AFAICS if polling is not used then no state
>>>>> changes would be handled, no? At least I don't see any snd_pcm_state() 
>>>>> call
>>>>> outside of alsa_poll_handler().
>>>> I have no idea but this fixes the problem (and does the same that can be
>>>> also done from command line but nobody can find that command line option)
>>>> so unless somebody has a better idea could this be merged as a fix for
>>>> now?
>>> Well, I understand that if fixes the misbehaviour you encountered. But how
>>> helpful would it be if it then breaks behaviour for other people instead?
>> What behaviour would it break and how?
> There are only a bunch of ALSA states handled right now in the QEMU Alsa
> driver (see alsa_poll_handler()):
>
>     state = snd_pcm_state (hlp->handle);
>     switch (state) {
>     case SND_PCM_STATE_SETUP:
>         alsa_recover (hlp->handle);
>         break;
>
>     case SND_PCM_STATE_XRUN:
>         alsa_recover (hlp->handle);
>         break;
>
>     case SND_PCM_STATE_SUSPENDED:
>         alsa_resume (hlp->handle);
>         break;
>
>     case SND_PCM_STATE_PREPARED:
>         audio_run(hlp->s, "alsa run (prepared)");
>         break;
>
>     case SND_PCM_STATE_RUNNING:
>         audio_run(hlp->s, "alsa run (running)");
>         break;
>
> For instance in poll mode it recovers in case of an xrun, which happens on
> audio output if the audio output data was not delivered by the application in
> time.
>
> The other case is when the system was suspended (standby). It should also
> recover the audio session here.

Hi Christian,

I think the timer based mode works fine. snd_pcm_readi() and
snd_pcm_writei() return -EPIPE in case of a xrun and -ESTRPIPE if a
suspend event occurred. Both cases are handled in alsa_write(). The
-ESTRPIPE case is missing in alsa_read(), which may be a mistake. I
don't think it's possible alsa_read() and alsa_write() get called if the
ALSA system is in state SND_PCM_STATE_SETUP.

The write_loop() example code at
https://www.alsa-project.org/alsa-doc/alsa-lib/examples.html in file
test/pcm.c also doesn't use the snd_pcm_state() function. Please have a
look at write_loop() in test/pcm.c and compare it with
write_and_poll_loop() in the same file.

With best regards
Volker

> Now I haven't tested whether these would work in callback mode right now, but
> looking at the code suggests that they might not.
>
>>> I think it would be better to add a 2nd patch that would handle state 
>>> changes
>>> in callback mode. That would satisfy both groups of people. AFAICS
>>> snd_pcm_state() can be called both in polling mode and callback mode.
>> I can't do that because I don't quite know neither alsa nor audio in QEMU 
>> so I have no idea what to do. Can you give more clues?
> Well, as a starting point you might try whether these cases described above
> would still work in callback mode. Maybe it is even working, who knows.
>
> /Christian
>
>>> Just my 2 cents. Of course it's up to Gerd to decide.
>> If you know it would break something I agree it should be fixed and I can 
>> try but I could not reproduce any breakage and most people likely use 
>> other audio backends so unlikely to encounter problems with alsa.
>>
>> Regards,
>> BALATON Zoltan
>


Reply via email to