static void alsa_log(snd_pcm_hw_params_t* hw_params, snd_pcm_sw_params_t* sw_params) { unsigned period_time; snd_pcm_uframes_t period_size; unsigned period_count; unsigned buffer_time; snd_pcm_uframes_t buffer_size; unsigned tick_time; snd_pcm_uframes_t xfer_align; snd_pcm_hw_params_get_period_time(hw_params, &period_time, 0); snd_pcm_hw_params_get_period_size(hw_params, &period_size, 0); snd_pcm_hw_params_get_periods(hw_params, &period_count, 0); snd_pcm_hw_params_get_buffer_time(hw_params, &buffer_time, 0); snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size); snd_pcm_hw_params_get_tick_time(hw_params, &tick_time, 0); log_std(("sound:alsa: hw period_time %g [us], period_size %d, periods %d, buffer_time %g [us], buffer_size %d, tick_time %g [us]\n", (double)(period_time / 1000000.0), (unsigned)period_size, (unsigned)period_count, (double)(buffer_time / 1000000.0), (unsigned)buffer_size, (double)(tick_time / 1000000.0) )); snd_pcm_sw_params_get_xfer_align(sw_params, &xfer_align); log_std(("sound:alsa: sw xfer_align %d\n", (unsigned)xfer_align )); }
static void set_params(void) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size; int err; size_t n; snd_pcm_uframes_t xfer_align; unsigned int rate; snd_pcm_uframes_t start_threshold, stop_threshold; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, params); if (err < 0) { error(_("Broken configuration for this PCM: no configurations available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { error(_("Access type not available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_format(handle, params, hwparams.format); if (err < 0) { error(_("Sample format non available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); if (err < 0) { error(_("Channels count non available")); exit(EXIT_FAILURE); } #if 0 err = snd_pcm_hw_params_set_periods_min(handle, params, 2); assert(err >= 0); #endif rate = hwparams.rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0); assert(err >= 0); if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) { if (!quiet_mode) { char plugex[64]; const char *pcmname = snd_pcm_name(handle); fprintf(stderr, _("Warning: rate is not accurate (requested = %iHz, got = %iHz)\n"), rate, hwparams.rate); if (! pcmname || strchr(snd_pcm_name(handle), ':')) *plugex = 0; else snprintf(plugex, sizeof(plugex), "(-Dplug:%s)", snd_pcm_name(handle)); fprintf(stderr, _(" please, try the plug plugin %s\n"), plugex); } } rate = hwparams.rate; if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0); assert(err >= 0); if (buffer_time > 500000) buffer_time = 500000; } if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0); assert(err >= 0); if (buffer_time > 0) { err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); } else { err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_frames); } assert(err >= 0); err = snd_pcm_hw_params(handle, params); if (err < 0) { error(_("Unable to install hw params:")); snd_pcm_hw_params_dump(params, log); exit(EXIT_FAILURE); } snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size(params, &buffer_size); if (chunk_size == buffer_size) { error(_("Can't use period equal to buffer size (%lu == %lu)"), chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align); if (err < 0) { error(_("Unable to obtain xfer align\n")); exit(EXIT_FAILURE); } if (sleep_min) xfer_align = 1; err = snd_pcm_sw_params_set_sleep_min(handle, swparams, sleep_min); assert(err >= 0); if (avail_min < 0) n = chunk_size; else n = (double) rate * avail_min / 1000000; err = snd_pcm_sw_params_set_avail_min(handle, swparams, n); // round up to closest transfer boundary n = (buffer_size / xfer_align) * xfer_align; start_threshold = n; if (start_threshold < 1) start_threshold = 1; if (start_threshold > n) start_threshold = n; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err >= 0); stop_threshold = buffer_size; err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); assert(err >= 0); err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align); assert(err >= 0); if (snd_pcm_sw_params(handle, swparams) < 0) { error(_("unable to install sw params:")); snd_pcm_sw_params_dump(swparams, log); exit(EXIT_FAILURE); } bits_per_sample = snd_pcm_format_physical_width(hwparams.format); bits_per_frame = bits_per_sample * hwparams.channels; chunk_bytes = chunk_size * bits_per_frame / 8; audiobuf = realloc(audiobuf, chunk_bytes); if (audiobuf == NULL) { error(_("not enough memory")); exit(EXIT_FAILURE); } // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size); }
static size_t alsa_configure (void) { //<init: size_t chunk_bytes, bits_per_sample, bits_per_frame = 0; snd_pcm_uframes_t chunk_size, buffer_size = 0; snd_pcm_hw_params_t *params; unsigned int rate = DEFAULT_SPEED; int err; snd_pcm_hw_params_alloca (¶ms); //> //<defaults: err = snd_pcm_hw_params_any (AHandle, params); if (err < 0) { fprintf (stderr, "Broken configuration for this PCM: no configurations available"); exit (EXIT_FAILURE); } //> //<Format: err = snd_pcm_hw_params_set_format (AHandle, params, DEFAULT_FORMAT); if (err < 0) { fprintf (stderr, "Sample format non available"); exit (EXIT_FAILURE); } //> //<Channels: err = snd_pcm_hw_params_set_channels (AHandle, params, 1); if (err < 0) { fprintf (stderr, "Channels count non available"); exit (EXIT_FAILURE); } //> //<Rate: err = snd_pcm_hw_params_set_rate_near (AHandle, params, &rate, 0); assert (err >= 0); //> //<Access Mode: err = snd_pcm_hw_params_set_access (AHandle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { fprintf (stderr, "Access type not available"); exit (EXIT_FAILURE); } //> //< Set things explicitly if DEBUG #ifdef DEBUG //<Compute buffer_time: unsigned int period_time = 0; unsigned int buffer_time = 0; snd_pcm_uframes_t period_frames = 0; snd_pcm_uframes_t buffer_frames = 0; // affected by defined buffer_size (e.g. via asoundrc) if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time (params, &buffer_time, 0); assert (err >= 0); if (buffer_time > 500000) //usecs buffer_time = 500000; } //> //<Compute period_time: if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near (AHandle, params, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near (AHandle, params, &period_frames, 0); assert (err >= 0); if (buffer_time > 0) { err = snd_pcm_hw_params_set_buffer_time_near (AHandle, params, &buffer_time, 0); } else { err = snd_pcm_hw_params_set_buffer_size_near (AHandle, params, &buffer_frames); } assert (err >= 0); //> #endif //> //<Commit hw params: err = snd_pcm_hw_params (AHandle, params); if (err < 0) { fprintf (stderr, "Unable to install hw params:"); exit (EXIT_FAILURE); } //> //<finalize chunk_size and buffer_size: snd_pcm_hw_params_get_period_size (params, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size (params, &buffer_size); if (chunk_size == buffer_size) { fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size); exit (EXIT_FAILURE); } //> //< If DEBUG: SW Params Configure transfer: #ifdef DEBUG size_t n; snd_pcm_uframes_t xfer_align; snd_pcm_uframes_t start_threshold, stop_threshold; int start_delay = 5; int stop_delay = 0; snd_pcm_sw_params_t *swParams; snd_pcm_sw_params_alloca (&swParams); snd_pcm_sw_params_current (AHandle, swParams); err = snd_pcm_sw_params_get_xfer_align (swParams, &xfer_align); if (err < 0) { fprintf (stderr, "Unable to obtain xfer align\n"); exit (EXIT_FAILURE); } // round up to closest transfer boundary n = (buffer_size / xfer_align) * xfer_align; if (start_delay <= 0) { start_threshold = (snd_pcm_uframes_t) (n + (double) rate * start_delay / 1000000); } else start_threshold = (snd_pcm_uframes_t) ((double) rate * start_delay / 1000000); if (start_threshold < 1) start_threshold = 1; if (start_threshold > n) start_threshold = n; err = snd_pcm_sw_params_set_start_threshold (AHandle, swParams, start_threshold); assert (err >= 0); if (stop_delay <= 0) stop_threshold = (snd_pcm_uframes_t) (buffer_size + (double) rate * stop_delay / 1000000); else stop_threshold = (snd_pcm_uframes_t) ((double) rate * stop_delay / 1000000); err = snd_pcm_sw_params_set_stop_threshold (AHandle, swParams, stop_threshold); assert (err >= 0); err = snd_pcm_sw_params_set_xfer_align (AHandle, swParams, xfer_align); assert (err >= 0); if (snd_pcm_sw_params (AHandle, swParams) < 0) { fprintf (stderr, "unable to install sw params:"); exit (EXIT_FAILURE); } #endif //> bits_per_sample = snd_pcm_format_physical_width (DEFAULT_FORMAT); bits_per_frame = bits_per_sample * 1; //mono chunk_bytes = chunk_size * bits_per_frame / 8; return chunk_bytes; }