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_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;
  }

          


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, 0, SNDRV_PCM_HW_PARAM_FORMAT,
                      -1);

          

The rule function is called when an application sets the number of channels. But an application can set the format before the number of channels. Thus you also need to define the inverse rule:

Example 5.7. 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;
  }

          


...and in the open callback:


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

          

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