Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Set the hardware parameters of the given ALSA device. Returns the
- * selected fragment settings in *period and *period_size */
- int pa_alsa_set_hw_params(
- snd_pcm_t *pcm_handle,
- pa_sample_spec *ss,
- uint32_t *periods,
- snd_pcm_uframes_t *period_size,
- snd_pcm_uframes_t tsched_size,
- pa_bool_t *use_mmap,
- pa_bool_t *use_tsched,
- pa_bool_t require_exact_channel_number) {
- int ret = -1;
- snd_pcm_uframes_t _period_size = *period_size;
- unsigned int _periods = *periods;
- snd_pcm_uframes_t buffer_size;
- unsigned int r = ss->rate;
- unsigned int c = ss->channels;
- pa_sample_format_t f = ss->format;
- snd_pcm_hw_params_t *hwparams;
- pa_bool_t _use_mmap = use_mmap && *use_mmap;
- pa_bool_t _use_tsched = use_tsched && *use_tsched;
- int dir;
- pa_assert(pcm_handle);
- pa_assert(ss);
- pa_assert(periods);
- pa_assert(period_size);
- snd_pcm_hw_params_alloca(&hwparams);
- if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
- goto finish;
- if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0)
- goto finish;
- if (_use_mmap) {
- if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
- /* mmap() didn't work, fall back to interleaved */
- if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
- goto finish;
- _use_mmap = FALSE;
- }
- } else if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
- goto finish;
- if (!_use_mmap)
- _use_tsched = FALSE;
- if ((ret = set_format(pcm_handle, hwparams, &f)) < 0)
- goto finish;
- if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0)
- goto finish;
- /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
- _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate);
- tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate);
- if (require_exact_channel_number) {
- if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0)
- goto finish;
- } else {
- if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0)
- goto finish;
- }
- if (_use_tsched) {
- _period_size = tsched_size;
- _periods = 1;
- pa_assert_se(snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size) == 0);
- pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r);
- }
- buffer_size = _periods * _period_size;
- if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0)
- goto finish;
- if (_periods > 0) {
- /* First we pass 0 as direction to get exactly what we asked
- * for. That this is necessary is presumably a bug in ALSA */
- dir = 0;
- if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
- dir = 1;
- if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
- dir = -1;
- if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
- goto finish;
- }
- }
- }
- if (_period_size > 0)
- if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)
- goto finish;
- if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
- goto finish;
- if (ss->rate != r)
- pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r);
- if (ss->channels != c)
- pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c);
- if (ss->format != f)
- pa_log_warn("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f));
- if ((ret = snd_pcm_prepare(pcm_handle)) < 0)
- goto finish;
- if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
- (ret = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0)
- goto finish;
- /* If the sample rate deviates too much, we need to resample */
- if (r < ss->rate*.95 || r > ss->rate*1.05)
- ss->rate = r;
- ss->channels = (uint8_t) c;
- ss->format = f;
- pa_assert(_periods > 0);
- pa_assert(_period_size > 0);
- *periods = _periods;
- *period_size = _period_size;
- if (use_mmap)
- *use_mmap = _use_mmap;
- if (use_tsched)
- *use_tsched = _use_tsched;
- ret = 0;
- snd_pcm_nonblock(pcm_handle, 1);
- finish:
- return ret;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement