/*
 * Reads and decodes configuration info from the specified ALSA card/device.
 */
static int read_alsa_device_config(alsa_device_profile * profile, struct pcm_config * config)
{
    ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)",
          profile->card, profile->device, profile->direction);

    if (profile->card < 0 || profile->device < 0) {
        return -EINVAL;
    }

    struct pcm_params * alsa_hw_params =
        pcm_params_get(profile->card, profile->device, profile->direction);
    if (alsa_hw_params == NULL) {
        return -EINVAL;
    }

    profile->min_period_size = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE);
    profile->max_period_size = pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE);

    profile->min_channel_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
    profile->max_channel_count = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);

    int ret = 0;

    /*
     * This Logging will be useful when testing new USB devices.
     */
#ifdef LOG_PCM_PARAMS
    log_pcm_params(alsa_hw_params);
#endif

    config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
    config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
    config->period_size = profile_calc_min_period_size(profile, config->rate);
    config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS);
    config->format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT));
#ifdef LOG_PCM_PARAMS
    log_pcm_config(config, "read_alsa_device_config");
#endif
    if (config->format == PCM_FORMAT_INVALID) {
        ret = -EINVAL;
    }

    pcm_params_free(alsa_hw_params);

    return ret;
}
bool profile_read_device_info(alsa_device_profile* profile)
{
    if (!profile_is_initialized(profile)) {
        return false;
    }

    /* let's get some defaults */
    read_alsa_device_config(profile, &profile->default_config);
    ALOGV("default_config chans:%d rate:%d format:%d count:%d size:%d",
          profile->default_config.channels, profile->default_config.rate,
          profile->default_config.format, profile->default_config.period_count,
          profile->default_config.period_size);

    struct pcm_params * alsa_hw_params = pcm_params_get(profile->card,
                                                        profile->device,
                                                        profile->direction);
    if (alsa_hw_params == NULL) {
        return false;
    }

    /* Formats */
    struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT);
    profile_enum_sample_formats(profile, format_mask);

    /* Channels */
    profile_enum_channel_counts(
            profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS),
            pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS));

    /* Sample Rates */
    profile_enum_sample_rates(
            profile, pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE),
            pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE));

    profile->is_valid = true;

    return true;
}
Esempio n. 3
0
static GstCaps *
gst_tinyalsa_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
{
  GstTinyalsaSink *sink = GST_TINYALSA_SINK (bsink);
  GstCaps *caps = NULL;
  GValue formats = { 0, };
  GValue format = { 0, };
  struct pcm_params *params = NULL;
  struct pcm_mask *mask;
  int rate_min, rate_max, channels_min, channels_max;
  guint16 m;

  GST_DEBUG_OBJECT (sink, "Querying caps");

  GST_OBJECT_LOCK (sink);

  if (sink->cached_caps) {
    GST_DEBUG_OBJECT (sink, "Returning cached caps");
    caps = gst_caps_ref (sink->cached_caps);
    goto done;
  }

  if (sink->pcm) {
    /* We can't query the device while it's open, so return current caps */
    caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink));
    goto done;
  }

  params = pcm_params_get (sink->card, sink->device, PCM_OUT);
  if (!params) {
    GST_ERROR_OBJECT (sink, "Could not get PCM params");
    goto done;
  }

  mask = pcm_params_get_mask (params, PCM_PARAM_FORMAT);
  m = (mask->bits[1] << 8) | mask->bits[0];

  if (!(m & SNDRV_PCM_FORMAT_ANY)) {
    GST_ERROR_OBJECT (sink, "Could not find any supported format");
    goto done;
  }

  caps = gst_caps_new_empty_simple ("audio/x-raw");

  g_value_init (&formats, GST_TYPE_LIST);
  g_value_init (&format, G_TYPE_STRING);

  if (m & (1 << SNDRV_PCM_FORMAT_S8)) {
    g_value_set_static_string (&format, "S8");
    gst_value_list_prepend_value (&formats, &format);
  }
  if (m & (1 << SNDRV_PCM_FORMAT_S16_LE)) {
    g_value_set_static_string (&format, "S16LE");
    gst_value_list_prepend_value (&formats, &format);
  }
  if (m & (1 << SNDRV_PCM_FORMAT_S24_LE)) {
    g_value_set_static_string (&format, "S24_32LE");
    gst_value_list_prepend_value (&formats, &format);
  }
  if (m & (1 << SNDRV_PCM_FORMAT_S32_LE)) {
    g_value_set_static_string (&format, "S32LE");
    gst_value_list_prepend_value (&formats, &format);
  }

  gst_caps_set_value (caps, "format", &formats);

  g_value_unset (&format);
  g_value_unset (&formats);

  /* This is a bit of a lie, since the device likely only supports some
   * standard rates in this range. We should probably filter the range to
   * those, standard audio rates but even that isn't guaranteed to be accurate.
   */
  rate_min = pcm_params_get_min (params, PCM_PARAM_RATE);
  rate_max = pcm_params_get_max (params, PCM_PARAM_RATE);

  if (rate_min == rate_max)
    gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate_min, NULL);
  else
    gst_caps_set_simple (caps, "rate", GST_TYPE_INT_RANGE, rate_min, rate_max,
        NULL);

  channels_min = pcm_params_get_min (params, PCM_PARAM_CHANNELS);
  channels_max = pcm_params_get_max (params, PCM_PARAM_CHANNELS);

  if (channels_min == channels_max)
    gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels_min, NULL);
  else
    gst_caps_set_simple (caps, "channels", GST_TYPE_INT_RANGE, channels_min,
        channels_max, NULL);

  gst_caps_replace (&sink->cached_caps, caps);

done:
  GST_OBJECT_UNLOCK (sink);

  GST_DEBUG_OBJECT (sink, "Got caps %" GST_PTR_FORMAT, caps);

  if (caps && filter) {
    GstCaps *intersection =
        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);

    gst_caps_unref (caps);
    caps = intersection;
  }

  if (params)
    pcm_params_free (params);

  return caps;
}
Esempio n. 4
0
int main(int argc, char **argv)
{
    unsigned int device = 0;
    unsigned int card = 0;
    int i;

    if (argc < 3) {
        fprintf(stderr, "Usage: %s -D card -d device\n", argv[0]);
        return 1;
    }

    /* parse command line arguments */
    argv += 1;
    while (*argv) {
        if (strcmp(*argv, "-D") == 0) {
            argv++;
            if (*argv)
                card = atoi(*argv);
        }
        if (strcmp(*argv, "-d") == 0) {
            argv++;
            if (*argv)
                device = atoi(*argv);
        }
        if (*argv)
            argv++;
    }

    printf("Info for card %u, device %u:\n", card, device);

    for (i = 0; i < 2; i++) {
        struct pcm_params *params;
        struct pcm_mask *m;
        unsigned int min;
        unsigned int max;

        printf("\nPCM %s:\n", i == 0 ? "out" : "in");

        params = pcm_params_get(card, device, i == 0 ? PCM_OUT : PCM_IN);
        if (params == NULL) {
            printf("Device does not exist.\n");
            continue;
        }

        m = pcm_params_get_mask(params, PCM_PARAM_ACCESS);
        if (m) { /* bitmask, refer to SNDRV_PCM_ACCESS_*, generally interleaved */
            printf("      Access:\t%#08x\n", m->bits[0]);
        }
        m = pcm_params_get_mask(params, PCM_PARAM_FORMAT);
        if (m) { /* bitmask, refer to: SNDRV_PCM_FORMAT_* */
            unsigned j, k, count = 0;
            const unsigned bitcount = sizeof(m->bits[0]) * 8;

            /* we only check first two format masks (out of 8) - others are zero. */
            printf("   Format[0]:\t%#08x\n", m->bits[0]);
            printf("   Format[1]:\t%#08x\n", m->bits[1]);

            /* print friendly format names, if they exist */
            for (k = 0; k < 2; ++k) {
                for (j = 0; j < bitcount; ++j) {
                    const char *name;

                    if (m->bits[k] & (1 << j)) {
                        name = pcm_get_format_name(j + k*bitcount);
                        if (name) {
                            if (count++ == 0) {
                                printf(" Format Name:\t");
                            } else {
                                printf (", ");
                            }
                            printf("%s", name);
                        }
                    }
                }
            }
            if (count) {
                printf("\n");
            }
        }
        m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT);
        if (m) { /* bitmask, should be 1: SNDRV_PCM_SUBFORMAT_STD */
            printf("   Subformat:\t%#08x\n", m->bits[0]);
        }
        min = pcm_params_get_min(params, PCM_PARAM_RATE);
        max = pcm_params_get_max(params, PCM_PARAM_RATE);
        printf("        Rate:\tmin=%uHz\tmax=%uHz\n", min, max);
        min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
        max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
        printf("    Channels:\tmin=%u\t\tmax=%u\n", min, max);
        min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
        max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
        printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max);
        min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
        max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
        printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max);
        min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
        max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
        printf("Period count:\tmin=%u\t\tmax=%u\n", min, max);

        pcm_params_free(params);
    }

    return 0;
}