At Fri, 26 Oct 2007 12:04:05 -0400, Sean McNamara wrote:
Hello,
I have opened a bug and recently submitted a patch for it on bugtrack: https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3470
All the details are there. But here is a 5-minute summary for you:
--The Problem-- (1) All plugins implementing the PCM interface, that I've tested so far, allow calling snd_*_hw_params on a stream when snd_*_state returns SND_PCM_STATE_PREPARED. (2) Applications have used this fact to their advantage, and sometimes employ lazy initialization of the hw params (initialize it once, get to another path in code, oh no wait! we need to initialize them differently...)
(3) Per the spec, calling snd_*_hw_params also makes the stream PREPARED, so calling snd_*_hw_params on a stream that has _either_ been explicitly prepared, _or_ had its hw_params previously set, will trigger this problem. (4) The ALSA<->PulseAudio plugin is an exception to (1) above; i.e., it triggers an assertion when exercising this functionality, as if to say, "I can't do that!" (5) Indeed, the PulseAudio client API forbids re-initialization of the parameters in question on a PulseAudio stream, after instantiation.
Yeah, the multiple call of hw_params and sw_params are allowed. I don't remember whether this is explicitly documented somewhere in the alsa-lib reference, but it's an empirical rule :) Ditto for prepare. snd_pcm_prepare can be called multiple times even in PREPARED state, just as a reset.
--The Solution-- Only perform the assertion if snd_pcm_state(io->pcm) != SND_PCM_STATE_PREPARED. The assertion is still useful for cases where the stream is mysteriously non-NULL and the stream has not already been prepared; I can't think of a valid case where: (1) The state is not SND_PCM_STATE_PREPARED, and (2) The underlying PulseAudio stream (pcm->stream) is non-NULL, and (3) snd_pcm_hw_params would be expected to do anything meaningful or correct. For this reason, I kept the assertion in, rather than just removing it (which by itself "fixes" the problem with alsaplayer and my test case, which is submitted with the patch.)
--Why It Works-- (1) This assertion might be a throwback from before ioplug was so smart; but apparently, ioplug will now call pulse_prepare, which reinitializes the underlying pulseaudio stream, after pulse_hw_params. (2) There is nothing in pulse_hw_params that actually requires any particular state out of pcm->stream. The underlying pulse stream is simply not used in this call. (3) ioplug catches the fact that the hw_params have been changed, and calls back to pulse_prepare to handle the underlying stream teardown and reinitialization (which pulse_prepare does correctly).
--Impact-- (1) At least one open source application, alsaplayer, can now play through the ALSA<->PulseAudio plugin, where it could never do so before. (2) The ALSA<->PulseAudio plugin is now more tightly compatible with the other alsa-lib and alsa-plugin backends (dmix, hw, asym, oss, jack, ...) (3) Older versions of sox might have also suffered from this bug, according to information here: http://www.pulseaudio.org/ticket/120 (although the Ubuntu 7.10 version of sox does not exhibit this behavior).
The patch looks good. I applied it to HG tree now.
Please check later whether it works for you. (If HG repo on hg-mirror isn't updated, try hg.alsa-project.org instead).
Thanks,
Takashi