[alsa-devel] Constraints and hw_params with highly configurable HW
Hi everybody
We're currently working on some neat enhancements for the still experimental snd_dice driver originally initiated by Clemens Ladisch. To list some of the new and already working features: * firmware loading, backed by a user-space command line utility * generic ALSA control support for mostly all device specific settings for all our (i.e. Weiss Engineering) DICE based products and last but not least * capture support * slave mode (external clock source support).
I'm currently debugging and fine-tuning things and that's where some questions arose. The initial implementation of Clemens tried to fetch all possible configurations of a device during probe in order to have all combinations of rates and channels at hand when it comes to formulate the constraints set within the ALSA pcm substream open callback. That's a nice approach but will fail with a lot of devices as their configurations can (and mostly will) be volatile. Our devices for instance feature several switches, options and alike which have heavy influence on the channel layout and sample rates and combination of both.
I consulted Takashi's documentation on constraints which suggests to "use the source" but I couldn't find any similar situation within other drivers (in case I should have missed something, just let me know of course).
Therefore I had the idea to define some maximum constraints and let the ALSA hw_params callback fail in case some settings or combinations are determined to be not supported during its invocation.
Is this viable? Could this be/is this consistent with the specs? If yes, would EINVAL an appropriate error code to return?
Regards Uli
Uli Franke wrote:
I'm currently debugging and fine-tuning things and that's where some questions arose. The initial implementation of Clemens tried to fetch all possible configurations of a device during probe in order to have all combinations of rates and channels at hand when it comes to formulate the constraints set within the ALSA pcm substream open callback. That's a nice approach but will fail with a lot of devices as their configurations can (and mostly will) be volatile. Our devices for instance feature several switches, options and alike which have heavy influence on the channel layout and sample rates and combination of both.
Then the constraints should be read from the device in the PCM open callback.
(If the settings can be controlled by software, they should by locked as long as some PCM device is open.)
Therefore I had the idea to define some maximum constraints and let the ALSA hw_params callback fail in case some settings or combinations are determined to be not supported during its invocation.
It wouldn't be a nice thing to do for the driver to set constraints that it already _knows_ it will not be able to support.
In the most common case, the hw_param callback happens immediately after the open callback, so it makes sense for .open to set constraints that reflect the current state of the device. It is still possible for the device state to change between .open and .hw_params, but that's the best the driver can do.
(What happens if the user flicks a switch while the software is playing?)
would EINVAL an appropriate error code to return?
Yes.
Regards, Clemens
Then the constraints should be read from the device in the PCM open callback.
No, that's not possible as the constraints will/can change in case you request a different sample rate for instance. Therefore the constraints won't be known until you set the rate for instance. And you will never be able to pre-fetch this information reliably as the DICE firmware is allowed to change its setup arbitrarily.
(If the settings can be controlled by software, they should by locked as long as some PCM device is open.)
This is obvious and is implemented like this.
But you have to keep in mind that there are other things which can not be locked. For instance the locking: If a device is synchronized to an external clock source, this clock source can disappear or be reconfigured at any time. How the device behaves in such situations depends strongly on the firmware. For example some devices provide autolocking which scans for lockable clocks in all frequency ranges. Others simply switch to internal clock. In all those situations its very likely that the stream layout will change. Even the clock caps can change at any time.
Therefore I had the idea to define some maximum constraints and let the ALSA hw_params callback fail in case some settings or combinations are determined to be not supported during its invocation.
It wouldn't be a nice thing to do for the driver to set constraints that it already _knows_ it will not be able to support.
Of course the driver should not set constraints which will never be supported. We're discussing the constraints which can not be determined without knowing some actual parameters.
As far as I can deduce from the call sequence the constraints are just a convenient way to let the user space open fail before .hw_params is actually called and free the programmer from the burden to formulate those similar and recurring checks over and over again in case the device constraints are static.
If the device reveals certain constraints only when some parameters are actually set and if the parameters are only known at .hw_param time, the constraint system must be bypassable. I don't see any drawback from this for other parts of the system. It only shows that the ALSA API simply can not abstract all devices perfectly. But that's OK and normal in real world applications. The important thing is that the user space application can assume equivalent behavior in either case. That's what's we're heading for.
Again: If I should miss something: I'm curious to learn about it.
In the most common case, the hw_param callback happens immediately after the open callback, so it makes sense for .open to set constraints that reflect the current state of the device.
Yes, but the "current state of the device" is not valid until you set the actual parameters which are not known at .open time.
It is still possible for the device state to change between .open and .hw_params, but that's the best the driver can do.
(What happens if the user flicks a switch while the software is playing?)
If the user flicks a switch while the software is playing the driver will get a notification and should take the appropriate measures to handle the new setup in case it changed. The driver already has been adapted to do so. For instance * react on locking events: pausing the PCM substreams in case the lock is lost * react on isochronous stream reconfiguration events: continue streaming when isochronous layout is compatible, kill streaming if not
would EINVAL an appropriate error code to return?
Great.
Regards Uli
Uli Franke wrote:
Then the constraints should be read from the device in the PCM open callback.
No, that's not possible as the constraints will/can change in case you request a different sample rate for instance. Therefore the constraints won't be known until you set the rate for instance.
The PCM constraints can represent arbitrary dependencies between the parameters, as long as they are known to the driver.
For example, one dependency (already handled by the ALSA framework) is between buffer size (length in frames) (A), buffer time (length in seconds) (B), and sample rate (C), with A = B * C. If any of these parameters changes, the allowed range of the other two is adjusted. For example, if a device allows sample rates between 48 kHz and 96 kHz (but none has yet been chosen), and if the buffer time is set to 0.5 s, then the interval for the buffer length is set to 24000...48000 frames.
My dice driver assumes that the number of channels depends only on the sample rate (and that only 48/96/192 kHz matter). The function dice_rate_constraint() is called when the number of channels in the snd_pcm_hw_params structure changes, and adjusts the allowed sample rates accordingly; the function dice_channels_constraint() is called when the sample rate changes, and adjusts the allowed number of channels accordingly.
And you will never be able to pre-fetch this information reliably as the DICE firmware is allowed to change its setup arbitrarily.
A generic DICE driver does not know what some arbitrary firmwares does, but for Weiss devices, you know the rules, don't you?
Regards, Clemens
participants (2)
-
Clemens Ladisch
-
Uli Franke