Constraints
Prev | Chapter 5. PCM Interface | Next

## Constraints

If your chip supports unconventional sample rates, or only the limited samples, you need to set a constraint for the condition.

For example, in order to restrict the sample rates in the some supported values, use `snd_pcm_hw_constraint_list()`. You need to call this function in the open callback.

Example 5.5. Example of Hardware Constraints

      static unsigned int rates[] =
              {4000, 10000, 22050, 44100};
      static struct snd_pcm_hw_constraint_list constraints_rates = {
              .count = ARRAY_SIZE(rates),
              .list = rates,
              .mask = 0,
      };

      static int snd_mychip_pcm_open(struct snd_pcm_substream *substream)
      {
              int err;
              ....
              err = snd_pcm_hw_constraint_list(substream->runtime, 0,
                                               SNDRV_PCM_HW_PARAM_RATE,
                                               &constraints_rates);
              if (err < 0)
                      return err;
              ....
      }

There are many different constraints. Look at `sound/pcm.h` for a complete list. You can even define your own constraint rules. For example, let's suppose my_chip can manage a substream of 1 channel if and only if the format is S16_LE, otherwise it supports any format specified in the snd_pcm_hardware structure (or in any other constraint_list). You can build a rule like this:

Example 5.6. Example of Hardware Constraints for Channels

      static int hw_rule_channels_by_format(struct snd_pcm_hw_params *params,
                                            struct snd_pcm_hw_rule *rule)
      {
              struct snd_interval *c = hw_param_interval(params,
                            SNDRV_PCM_HW_PARAM_CHANNELS);
              struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
              struct snd_interval ch;

              snd_interval_any(&ch);
              if (f->bits[0] == SNDRV_PCM_FMTBIT_S16_LE) {
                      ch.min = ch.max = 1;
                      ch.integer = 1;
                      return snd_interval_refine(c, &ch);
              }
              return 0;
      }

Then you need to call this function to add your rule:

      snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
                          hw_rule_channels_by_format, NULL,
                          SNDRV_PCM_HW_PARAM_FORMAT, -1);

The rule function is called when an application sets the PCM format, and it refines the number of channels accordingly. But an application may set the number of channels before setting the format. Thus you also need to define the inverse rule:

Example 5.7. Example of Hardware Constraints for Formats

      static int hw_rule_format_by_channels(struct snd_pcm_hw_params *params,
                                            struct snd_pcm_hw_rule *rule)
      {
              struct snd_interval *c = hw_param_interval(params,
                    SNDRV_PCM_HW_PARAM_CHANNELS);
              struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
              struct snd_mask fmt;

              snd_mask_any(&fmt);    /* Init the struct */
              if (c->min < 2) {
                      fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
                      return snd_mask_refine(f, &fmt);
              }
              return 0;
      }

...and in the open callback:

      snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
                          hw_rule_format_by_channels, NULL,
                          SNDRV_PCM_HW_PARAM_CHANNELS, -1);

I won't give more details here, rather I would like to say, “Luke, use the source.”

Prev | Up | Next
Atomicity | Home | Chapter 6. Control Interface