int getPcmParams(unsigned int i) { struct pcm_params *params; unsigned int min; unsigned int max; params = pcm_params_get(pcmnodes[i].card, pcmnodes[i].device, pcmnodes[i].flags); if (params == NULL) return -ENODEV; min = pcm_params_get_min(params, PCM_PARAM_RATE); max = pcm_params_get_max(params, PCM_PARAM_RATE); EXPECT_LE(min, max); /* 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); EXPECT_LE(min, max); /* 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); EXPECT_LE(min, max); /* 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); EXPECT_LE(min, max); /* 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); EXPECT_LE(min, max); /* printf("Period count:\tmin=%u\t\tmax=%u\n", min, max); */ pcm_params_free(params); return 0; }
static int validate_output_hardware_params(struct stream_out *out) { struct audio_device *adev = out->dev; struct pcm_params *params; unsigned int min; unsigned int max; params = pcm_params_get(adev->card, adev->device, PCM_OUT); if (params == NULL) { ALOGW("Device does not exist.\n"); return -1; } //always open the device with max capabilities if // input params are not supported min = pcm_params_get_min(params, PCM_PARAM_RATE); max = pcm_params_get_max(params, PCM_PARAM_RATE); ALOGI("hw supported Rate:\tmin=%uHz\tmax=%uHz\n", min, max); if((out->pcm_config.rate < min) || (out->pcm_config.rate > max)) { out->pcm_config.rate = max; } min = pcm_params_get_min(params, PCM_PARAM_CHANNELS); max = pcm_params_get_max(params, PCM_PARAM_CHANNELS); ALOGI("hw supported Channels:\tmin=%u\t\tmax=%u\n", min, max); if((out->pcm_config.channels < min) || (out->pcm_config.channels > max)) { out->pcm_config.channels = max; } min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS); max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS); ALOGI("hw supported Sample bits:\tmin=%u\t\tmax=%u\n", min, max); unsigned int bits_per_sample = format_to_bits(out->pcm_config.format); if((bits_per_sample < min) || (bits_per_sample > max)) { bits_per_sample = max; } out->pcm_config.format = bits_to_format(bits_per_sample); ALOGV("%s exit supported params %d,%d,%d,%d,%d",__func__, out->pcm_config.channels, out->pcm_config.rate, out->pcm_config.period_size, out->pcm_config.period_count, out->pcm_config.format); pcm_params_free(params); return 0; }
/* * 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; }
static int get_formats_tinyalsa(out123_handle *ao) { debug("get_formats_tinyalsa()"); mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr; if ( ao->rate >= pcm_params_get_min(ta->params, PCM_PARAM_RATE) && ao->rate <= pcm_params_get_max(ta->params, PCM_PARAM_RATE) && ao->channels >= pcm_params_get_min(ta->params, PCM_PARAM_CHANNELS) && ao->channels <= pcm_params_get_max(ta->params, PCM_PARAM_CHANNELS) ) { return MPG123_ENC_SIGNED_16; } else { return 0; } }
int check_param(struct pcm_params *params, unsigned int param, unsigned int value, char *param_name, char *param_unit) { unsigned int min; unsigned int max; int is_within_bounds = 1; min = pcm_params_get_min(params, param); if (value < min) { fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value, param_unit, min, param_unit); is_within_bounds = 0; } max = pcm_params_get_max(params, param); if (value > max) { fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value, param_unit, max, param_unit); is_within_bounds = 0; } return is_within_bounds; }
static gboolean gst_tinyalsa_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec) { GstTinyalsaSink *sink = GST_TINYALSA_SINK (asink); struct pcm_config config = { 0, }; struct pcm_params *params = NULL; int period_size_min, period_size_max; int periods_min, periods_max; pcm_config_from_spec (&config, spec); GST_DEBUG_OBJECT (sink, "Requesting %u periods of %u frames", config.period_count, config.period_size); params = pcm_params_get (sink->card, sink->device, PCM_OUT); if (!params) GST_ERROR_OBJECT (sink, "Could not get PCM params"); period_size_min = pcm_params_get_min (params, PCM_PARAM_PERIOD_SIZE); period_size_max = pcm_params_get_max (params, PCM_PARAM_PERIOD_SIZE); periods_min = pcm_params_get_min (params, PCM_PARAM_PERIODS); periods_max = pcm_params_get_max (params, PCM_PARAM_PERIODS); pcm_params_free (params); /* Snap period size/count to the permitted range */ config.period_size = CLAMP (config.period_size, period_size_min, period_size_max); config.period_count = CLAMP (config.period_count, periods_min, periods_max); /* mutex with getcaps */ GST_OBJECT_LOCK (sink); sink->pcm = pcm_open (sink->card, sink->device, PCM_OUT | PCM_NORESTART, &config); GST_OBJECT_UNLOCK (sink); if (!sink->pcm || !pcm_is_ready (sink->pcm)) { GST_ERROR_OBJECT (sink, "Could not open device: %s", pcm_get_error (sink->pcm)); goto fail; } if (pcm_prepare (sink->pcm) < 0) { GST_ERROR_OBJECT (sink, "Could not prepare device: %s", pcm_get_error (sink->pcm)); goto fail; } spec->segsize = pcm_frames_to_bytes (sink->pcm, config.period_size); spec->segtotal = config.period_count; GST_DEBUG_OBJECT (sink, "Configured for %u periods of %u frames", config.period_count, config.period_size); return TRUE; fail: if (sink->pcm) pcm_close (sink->pcm); return FALSE; }
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; }
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; }
static int validate_input_hardware_params(struct stream_in *in) { struct audio_device *adev = in->dev; struct pcm_params *params; unsigned int min; unsigned int max; params = pcm_params_get(adev->card, adev->device, PCM_IN); if (params == NULL) { ALOGW("Device does not exist.\n"); return -1; } /* always open the device with min capabilities if * input params are not supported */ min = pcm_params_get_min(params, PCM_PARAM_RATE); max = pcm_params_get_max(params, PCM_PARAM_RATE); ALOGI("hw supported Rate:\tmin=%uHz\tmax=%uHz\n", min, max); if((in->pcm_config.rate < min) || (in->pcm_config.rate > max)) { in->pcm_config.rate = min; } min = pcm_params_get_min(params, PCM_PARAM_CHANNELS); max = pcm_params_get_max(params, PCM_PARAM_CHANNELS); ALOGI("hw supported Channels:\tmin=%u\t\tmax=%u\n", min, max); if((in->pcm_config.channels < min) || (in->pcm_config.channels > max)) { in->pcm_config.channels = min; } min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS); max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS); ALOGI("hw supported Sample bits:\tmin=%u\t\tmax=%u\n", min, max); unsigned int bits_per_sample = format_to_bits(in->pcm_config.format); if((bits_per_sample < min) || (bits_per_sample > max)) { bits_per_sample = min; } in->pcm_config.format = bits_to_format(bits_per_sample); min = pcm_params_get_min(params, PCM_PARAM_PERIODS); max = pcm_params_get_max(params, PCM_PARAM_PERIODS); ALOGI("hw supported period_count:\tmin=%u\t\tmax=%u\n", min, max); if((in->pcm_config.period_count < min) || (in->pcm_config.period_count > max)) { in->pcm_config.period_count = min; } min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE); max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE); ALOGI("hw supported period_size:\tmin=%u\t\tmax=%u\n", min, max); if((in->pcm_config.period_size < min) || (in->pcm_config.period_size > max)) { in->pcm_config.period_size = min; } ALOGV("%s :: Exit supported params \ \r \t channels = %d, \ \r \t rate = %d, \ \r \t period_size = %d, \ \r \t period_count = %d, \ \r \t format = %d", __func__, in->pcm_config.channels,in->pcm_config.rate, in->pcm_config.period_size,in->pcm_config.period_count, in->pcm_config.format); pcm_params_free(params); return 0; }