static void getparams_periods(snd_pcm_t *handle, snd_pcm_hw_params_t *params, unsigned int *usecs, unsigned int *count, const char *id) { unsigned min = 0, max = 0; snd_pcm_hw_params_get_periods_min(params, &min, 0); snd_pcm_hw_params_get_periods_max(params, &max, 0); if (min && max) { if (verbose) fprintf(error_fp, "alsa: %s periods range between %u and %u. Want: %u\n", id, min, max, *count); if (*count < min) *count = min; if (*count > max) *count = max; } min = max = 0; snd_pcm_hw_params_get_period_time_min(params, &min, 0); snd_pcm_hw_params_get_period_time_max(params, &max, 0); if (min && max) { if (verbose) fprintf(error_fp, "alsa: %s period time range between %u and %u. Want: %u\n", id, min, max, *usecs); if (*usecs < min) *usecs = min; if (*usecs > max) *usecs = max; } }
optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMinAsInt(std::map<String,String> Parameters) { if (!Parameters.count("CARD")) return optional<int>::nothing; // obtain information from given sound card String pcm_name = "hw:" + Parameters["CARD"]; snd_pcm_t* pcm_handle = NULL; if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing; snd_pcm_hw_params_t* hwparams; snd_pcm_hw_params_alloca(&hwparams); if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { snd_pcm_close(pcm_handle); return optional<int>::nothing; } int dir = 0; uint periods_min; if (snd_pcm_hw_params_get_periods_min(hwparams, &periods_min, &dir) < 0) { snd_pcm_close(pcm_handle); return optional<int>::nothing; } snd_pcm_close(pcm_handle); return (int) periods_min; }
static int set_hwparams (GstAlsaSink * alsa) { guint rrate; gint err; snd_pcm_hw_params_t *params; guint period_time, buffer_time; snd_pcm_hw_params_malloc (¶ms); GST_DEBUG_OBJECT (alsa, "Negotiating to %d channels @ %d Hz (format = %s) " "SPDIF (%d)", alsa->channels, alsa->rate, snd_pcm_format_name (alsa->format), alsa->iec958); /* start with requested values, if we cannot configure alsa for those values, * we set these values to -1, which will leave the default alsa values */ buffer_time = alsa->buffer_time; period_time = alsa->period_time; retry: /* choose all parameters */ CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config); /* set the interleaved read/write format */ CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access), wrong_access); /* set the sample format */ if (alsa->iec958) { /* Try to use big endian first else fallback to le and swap bytes */ if (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format) < 0) { alsa->format = SND_PCM_FORMAT_S16_LE; alsa->need_swap = TRUE; GST_DEBUG_OBJECT (alsa, "falling back to little endian with swapping"); } else { alsa->need_swap = FALSE; } } CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format), no_sample_format); /* set the count of channels */ CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels), no_channels); /* set the stream rate */ rrate = alsa->rate; CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL), no_rate); #ifndef GST_DISABLE_GST_DEBUG /* get and dump some limits */ { guint min, max; snd_pcm_hw_params_get_buffer_time_min (params, &min, NULL); snd_pcm_hw_params_get_buffer_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u", alsa->buffer_time, min, max); snd_pcm_hw_params_get_period_time_min (params, &min, NULL); snd_pcm_hw_params_get_period_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u", alsa->period_time, min, max); snd_pcm_hw_params_get_periods_min (params, &min, NULL); snd_pcm_hw_params_get_periods_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); } #endif /* now try to configure the buffer time and period time, if one * of those fail, we fall back to the defaults and emit a warning. */ if (buffer_time != -1 && !alsa->iec958) { /* set the buffer time */ if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, &buffer_time, NULL)) < 0) { GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set buffer time %i for playback: %s", buffer_time, snd_strerror (err))); /* disable buffer_time the next round */ buffer_time = -1; goto retry; } GST_DEBUG_OBJECT (alsa, "buffer time %u", buffer_time); } if (period_time != -1 && !alsa->iec958) { /* set the period time */ if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params, &period_time, NULL)) < 0) { GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set period time %i for playback: %s", period_time, snd_strerror (err))); /* disable period_time the next round */ period_time = -1; goto retry; } GST_DEBUG_OBJECT (alsa, "period time %u", period_time); } /* Set buffer size and period size manually for SPDIF */ if (G_UNLIKELY (alsa->iec958)) { snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE; snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE; CHECK (snd_pcm_hw_params_set_buffer_size_near (alsa->handle, params, &buffer_size), buffer_size); CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params, &period_size, NULL), period_size); } /* write the parameters to device */ CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); /* now get the configured values */ CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size), buffer_size); CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, NULL), period_size); GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size, alsa->period_size); snd_pcm_hw_params_free (params); return 0; /* ERRORS */ no_config: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Broken configuration for playback: no configurations available: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } wrong_access: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Access type not available for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_sample_format: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Sample format not available for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_channels: { gchar *msg = NULL; if ((alsa->channels) == 1) msg = g_strdup (_("Could not open device for playback in mono mode.")); if ((alsa->channels) == 2) msg = g_strdup (_("Could not open device for playback in stereo mode.")); if ((alsa->channels) > 2) msg = g_strdup_printf (_ ("Could not open device for playback in %d-channel mode."), alsa->channels); GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg), ("%s", snd_strerror (err))); g_free (msg); snd_pcm_hw_params_free (params); return err; } no_rate: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Rate %iHz not available for playback: %s", alsa->rate, snd_strerror (err))); return err; } buffer_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get buffer size for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } period_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get period size for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } set_hw_params: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set hw params for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } }
static GF_Err ALSA_ConfigureOutput(GF_AudioOutput*dr, u32 *SampleRate, u32 *NbChannels, u32 *nbBitsPerSample, u32 channel_cfg) { snd_pcm_hw_params_t *hw_params = NULL; int err; int nb_bufs, sr, val, period_time; ALSAContext *ctx = (ALSAContext*)dr->opaque; if (!ctx) return GF_BAD_PARAM; /*close device*/ if (ctx->playback_handle) { snd_pcm_close(ctx->playback_handle); ctx->playback_handle = NULL; } if (ctx->wav_buf) free(ctx->wav_buf); ctx->wav_buf = NULL; err = snd_pcm_open(&ctx->playback_handle, ctx->dev_name, SND_PCM_STREAM_PLAYBACK, 0/*SND_PCM_NONBLOCK*/); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot open audio device %s: %s\n", ctx->dev_name, snd_strerror (err)) ); return GF_IO_ERR; } err = snd_pcm_hw_params_malloc(&hw_params); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot allocate hardware params: %s\n", snd_strerror (err)) ); goto err_exit; } err = snd_pcm_hw_params_any(ctx->playback_handle, hw_params); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot initialize hardware params: %s\n", snd_strerror (err)) ); goto err_exit; } err = snd_pcm_hw_params_set_access(ctx->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set access type: %s\n", snd_strerror (err)) ); goto err_exit; } /*set output format*/ ctx->nb_ch = (int) (*NbChannels); ctx->block_align = ctx->nb_ch; if ((*nbBitsPerSample) == 16) { ctx->block_align *= 2; err = snd_pcm_hw_params_set_format(ctx->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE); } else { err = snd_pcm_hw_params_set_format(ctx->playback_handle, hw_params, SND_PCM_FORMAT_U8); } if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set sample format: %s\n", snd_strerror (err)) ); goto err_exit; } /*set output sample rate*/ if (ctx->force_sr) *SampleRate = ctx->force_sr; sr = *SampleRate; err = snd_pcm_hw_params_set_rate_near(ctx->playback_handle, hw_params, SampleRate, 0); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set sample rate: %s\n", snd_strerror (err)) ); goto err_exit; } if (sr != *SampleRate) { GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[ALSA] Sample rate %d not supported, using %d instead\n", sr, *SampleRate ) ); sr = *SampleRate; } /*set output channels*/ err = snd_pcm_hw_params_set_channels_near(ctx->playback_handle, hw_params, NbChannels); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set channel count: %s\n", snd_strerror (err)) ); goto err_exit; } if (ctx->nb_ch != *NbChannels) { GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[ALSA] %d channels not supported - using %d instead\n", ctx->nb_ch, *NbChannels ) ); ctx->block_align /= ctx->nb_ch; ctx->nb_ch = *NbChannels; ctx->block_align *= ctx->nb_ch; } err = snd_pcm_hw_params(ctx->playback_handle, hw_params); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set parameters: %s\n", snd_strerror (err)) ); goto err_exit; } /* Set number of buffers*/ snd_pcm_hw_params_get_periods_min(hw_params, &val, 0); nb_bufs = (ctx->num_buffers>val) ? ctx->num_buffers : val; err = snd_pcm_hw_params_set_periods_near(ctx->playback_handle, hw_params, &nb_bufs, 0); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set number of HW buffers (%d): %s\n", nb_bufs, snd_strerror(err) )); goto err_exit; } /* Set total buffer size*/ if (ctx->total_duration) { ctx->buf_size = (sr * ctx->total_duration)/1000; } else { ctx->buf_size = 2048; } ctx->buf_size /= nb_bufs; err = snd_pcm_hw_params_set_period_size_near(ctx->playback_handle, hw_params, (snd_pcm_uframes_t *)&ctx->buf_size, 0); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set HW buffer size (%d): %s\n", ctx->buf_size, snd_strerror(err) )); goto err_exit; } /*get complete buffer size*/ snd_pcm_hw_params_get_buffer_size(hw_params, (snd_pcm_uframes_t *)&ctx->buf_size); ctx->buf_size *= ctx->block_align; /*get period time*/ snd_pcm_hw_params_get_period_time(hw_params, &period_time, 0); snd_pcm_hw_params_free (hw_params); hw_params = NULL; ctx->delay = (ctx->buf_size*1000) / (sr*ctx->block_align); /*allocate a single buffer*/ ctx->wav_buf = malloc(ctx->buf_size*sizeof(char)); if(!ctx->wav_buf) return GF_OUT_OF_MEM; memset(ctx->wav_buf, 0, ctx->buf_size*sizeof(char)); GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[ALSA] Setup %d ch @ %d hz - %d periods of %d us - total buffer size %d - overall delay %d ms\n", ctx->nb_ch, sr, nb_bufs, period_time, ctx->buf_size, ctx->delay)); return GF_OK; err_exit: if (hw_params) snd_pcm_hw_params_free(hw_params); snd_pcm_close(ctx->playback_handle); ctx->playback_handle = NULL; return GF_IO_ERR; }
/* ------- PCM INITS --------------------------------- */ static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params,int *chs) { #ifndef ALSAAPI9 unsigned int rrate; int err, dir; int channels_allocated = 0; /* choose all parameters */ err = snd_pcm_hw_params_any(handle, params); if (err < 0) { check_error(err,"Broken configuration: no configurations available"); return err; } /* set the nointerleaved read/write format */ err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); if (err >= 0) { #ifdef ALSAMM_DEBUG if(sys_verbose) post("Access type %s available","SND_PCM_ACCESS_MMAP_NONINTERLEAVED"); #endif } else{ check_error(err,"No Accesstype SND_PCM_ACCESS_MMAP_NONINTERLEAVED"); return err; } /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, params, ALSAMM_FORMAT); if (err < 0) { check_error(err,"Sample format not available for playback"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("Setting format to %s",snd_pcm_format_name(ALSAMM_FORMAT)); #endif /* first check samplerate since channels numbers are samplerate dependent (double speed) */ /* set the stream rate */ rrate = alsamm_sr; #ifdef ALSAMM_DEBUG if(sys_verbose) post("Samplerate request: %i Hz",rrate); #endif dir=-1; err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, &dir); if (err < 0) { check_error(err,"Rate not available"); return err; } if (rrate != alsamm_sr) { post("Warning: rate %iHz doesn't match requested %iHz", rrate,alsamm_sr); alsamm_sr = rrate; } else if(sys_verbose) post("Samplerate is set to %iHz",alsamm_sr); /* Info on channels */ { int maxchs,minchs,channels = *chs; if((err = snd_pcm_hw_params_get_channels_max(params, (unsigned int *)&maxchs)) < 0){ check_error(err,"Getting channels_max not available"); return err; } if((err = snd_pcm_hw_params_get_channels_min(params, (unsigned int *)&minchs)) < 0){ check_error(err,"Getting channels_min not available"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("Getting channels:min=%d, max= %d for request=%d",minchs,maxchs,channels); #endif if(channels < 0)channels=maxchs; if(channels > maxchs)channels = maxchs; if(channels < minchs)channels = minchs; if(channels != *chs) post("requested channels=%d but used=%d",*chs,channels); *chs = channels; #ifdef ALSAMM_DEBUG if(sys_verbose) post("trying to use channels: %d",channels); #endif } /* set the count of channels */ err = snd_pcm_hw_params_set_channels(handle, params, *chs); if (err < 0) { check_error(err,"Channels count not available"); return err; } /* testing for channels */ if((err = snd_pcm_hw_params_get_channels(params,(unsigned int *)chs)) < 0) check_error(err,"Get channels not available"); #ifdef ALSAMM_DEBUG else if(sys_verbose) post("When setting channels count and got %d",*chs); #endif /* if buffersize is set use this instead buffertime */ if(alsamm_buffersize > 0){ #ifdef ALSAMM_DEBUG if(sys_verbose) post("hw_params: ask for max buffersize of %d samples", (unsigned int) alsamm_buffersize ); #endif alsamm_buffer_size = alsamm_buffersize; err = snd_pcm_hw_params_set_buffer_size_near(handle, params, (unsigned long *)&alsamm_buffer_size); if (err < 0) { check_error(err,"Unable to set max buffer size"); return err; } } else{ if(alsamm_buffertime <= 0) /* should never happen, but use 20ms */ alsamm_buffertime = 20000; #ifdef ALSAMM_DEBUG if(sys_verbose) post("hw_params: ask for max buffertime of %d ms", (unsigned int) (alsamm_buffertime*0.001) ); #endif err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &alsamm_buffertime, &dir); if (err < 0) { check_error(err,"Unable to set max buffer time"); return err; } } err = snd_pcm_hw_params_get_buffer_time(params, (unsigned int *)&alsamm_buffertime, &dir); if (err < 0) { check_error(err,"Unable to get buffer time"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("hw_params: got buffertime to %f ms", (float) (alsamm_buffertime*0.001)); #endif err = snd_pcm_hw_params_get_buffer_size(params, (unsigned long *)&alsamm_buffer_size); if (err < 0) { check_error(err,"Unable to get buffer size"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("hw_params: got buffersize to %d samples",(int) alsamm_buffer_size); #endif err = snd_pcm_hw_params_get_period_size(params, (unsigned long *)&alsamm_period_size, &dir); if (err > 0) { check_error(err,"Unable to get period size"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("Got period size of %d", (int) alsamm_period_size); #endif { unsigned int pmin,pmax; err = snd_pcm_hw_params_get_periods_min(params, &pmin, &dir); if (err > 0) { check_error(err,"Unable to get period size"); return err; } err = snd_pcm_hw_params_get_periods_min(params, &pmax, &dir); if (err > 0) { check_error(err,"Unable to get period size"); return err; } /* use maximum of periods */ if( alsamm_periods <= 0) alsamm_periods = pmax; alsamm_periods = (alsamm_periods > pmax)?pmax:alsamm_periods; alsamm_periods = (alsamm_periods < pmin)?pmin:alsamm_periods; err = snd_pcm_hw_params_set_periods(handle, params, alsamm_periods, dir); if (err > 0) { check_error(err,"Unable to set periods"); return err; } err = snd_pcm_hw_params_get_periods(params, &pmin, &dir); if (err > 0) { check_error(err,"Unable to get periods"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("Got periods of %d, where periodsmin=%d, periodsmax=%d", alsamm_periods,pmin,pmax); #endif } /* write the parameters to device */ err = snd_pcm_hw_params(handle, params); if (err < 0) { check_error(err,"Unable to set hw params"); return err; } #endif /* ALSAAPI9 */ return 0; }
static int set_hwparams (GstAlsaSrc * alsa) { guint rrate; gint err; snd_pcm_hw_params_t *params; snd_pcm_hw_params_malloc (¶ms); /* choose all parameters */ CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config); /* set the interleaved read/write format */ CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access), wrong_access); /* set the sample format */ CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format), no_sample_format); /* set the count of channels */ CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels), no_channels); /* set the stream rate */ rrate = alsa->rate; CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL), no_rate); if (rrate != alsa->rate) goto rate_match; #ifndef GST_DISABLE_GST_DEBUG /* get and dump some limits */ { guint min, max; snd_pcm_hw_params_get_buffer_time_min (params, &min, NULL); snd_pcm_hw_params_get_buffer_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u", alsa->buffer_time, min, max); snd_pcm_hw_params_get_period_time_min (params, &min, NULL); snd_pcm_hw_params_get_period_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u", alsa->period_time, min, max); snd_pcm_hw_params_get_periods_min (params, &min, NULL); snd_pcm_hw_params_get_periods_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); } #endif if (alsa->buffer_time != -1) { /* set the buffer time */ CHECK (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, &alsa->buffer_time, NULL), buffer_time); GST_DEBUG_OBJECT (alsa, "buffer time %u", alsa->buffer_time); } if (alsa->period_time != -1) { /* set the period time */ CHECK (snd_pcm_hw_params_set_period_time_near (alsa->handle, params, &alsa->period_time, NULL), period_time); GST_DEBUG_OBJECT (alsa, "period time %u", alsa->period_time); } /* write the parameters to device */ CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size), buffer_size); CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, NULL), period_size); snd_pcm_hw_params_free (params); return 0; /* ERRORS */ no_config: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Broken configuration for recording: no configurations available: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } wrong_access: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Access type not available for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_sample_format: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Sample format not available for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_channels: { gchar *msg = NULL; if ((alsa->channels) == 1) msg = g_strdup (_("Could not open device for recording in mono mode.")); if ((alsa->channels) == 2) msg = g_strdup (_("Could not open device for recording in stereo mode.")); if ((alsa->channels) > 2) msg = g_strdup_printf (_ ("Could not open device for recording in %d-channel mode"), alsa->channels); GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg), ("%s", snd_strerror (err))); g_free (msg); snd_pcm_hw_params_free (params); return err; } no_rate: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Rate %iHz not available for recording: %s", alsa->rate, snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } rate_match: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Rate doesn't match (requested %iHz, get %iHz)", alsa->rate, err)); snd_pcm_hw_params_free (params); return -EINVAL; } buffer_time: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set buffer time %i for recording: %s", alsa->buffer_time, snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } buffer_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get buffer size for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } period_time: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set period time %i for recording: %s", alsa->period_time, snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } period_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get period size for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } set_hw_params: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set hw params for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } }
bool CAESinkALSA::InitializeHW(const ALSAConfig &inconfig, ALSAConfig &outconfig) { snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_alloca(&hw_params); memset(hw_params, 0, snd_pcm_hw_params_sizeof()); snd_pcm_hw_params_any(m_pcm, hw_params); snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); unsigned int sampleRate = inconfig.sampleRate; unsigned int channelCount = inconfig.channels; #if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC) // alsa/kernel lies, so map everything to 44100 or 48000 switch(sampleRate) { case 11025: case 22050: case 88200: case 176400: sampleRate = 44100; break; case 8000: case 16000: case 24000: case 32000: case 96000: case 192000: case 384000: sampleRate = 48000; break; } #endif snd_pcm_hw_params_set_rate_near (m_pcm, hw_params, &sampleRate, NULL); snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount); /* ensure we opened X channels or more */ if (inconfig.channels > channelCount) { CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Unable to open the required number of channels"); } /* update outconfig */ outconfig.channels = channelCount; snd_pcm_format_t fmt = AEFormatToALSAFormat(inconfig.format); outconfig.format = inconfig.format; if (fmt == SND_PCM_FORMAT_UNKNOWN) { /* if we dont support the requested format, fallback to float */ fmt = SND_PCM_FORMAT_FLOAT; outconfig.format = AE_FMT_FLOAT; } /* try the data format */ if (snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0) { /* if the chosen format is not supported, try each one in decending order */ CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(outconfig.format)); for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1)) { if (AE_IS_RAW(i) || i == AE_FMT_MAX) continue; if (m_passthrough && i != AE_FMT_S16BE && i != AE_FMT_S16LE) continue; fmt = AEFormatToALSAFormat(i); if (fmt == SND_PCM_FORMAT_UNKNOWN || snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0) { fmt = SND_PCM_FORMAT_UNKNOWN; continue; } int fmtBits = CAEUtil::DataFormatToBits(i); int bits = snd_pcm_hw_params_get_sbits(hw_params); if (bits != fmtBits) { /* if we opened in 32bit and only have 24bits, pack into 24 */ if (fmtBits == 32 && bits == 24) i = AE_FMT_S24NE4; else continue; } /* record that the format fell back to X */ outconfig.format = i; CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(outconfig.format)); break; } /* if we failed to find a valid output format */ if (fmt == SND_PCM_FORMAT_UNKNOWN) { CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to find a suitable output format"); return false; } } unsigned int periods; snd_pcm_uframes_t periodSize, bufferSize; snd_pcm_hw_params_get_periods_min(hw_params, &periods, NULL); snd_pcm_hw_params_get_period_size_min(hw_params, &periodSize, NULL); snd_pcm_hw_params_get_buffer_size_min(hw_params, &bufferSize); CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Min: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize); snd_pcm_hw_params_get_periods_max(hw_params, &periods, NULL); snd_pcm_hw_params_get_period_size_max(hw_params, &periodSize, NULL); snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize); CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Max: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize); snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize); snd_pcm_hw_params_get_period_size_max(hw_params, &periodSize, NULL); /* We want to make sure, that we have max 200 ms Buffer with a periodSize of approx 50 ms. Choosing a higher bufferSize will cause problems with menu sounds. Buffer will be increased after those are fixed. */ periodSize = std::min(periodSize, (snd_pcm_uframes_t) sampleRate / 20); bufferSize = std::min(bufferSize, (snd_pcm_uframes_t) sampleRate / 5); #if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC) // must be pot for pivos. bufferSize = CheckNP2(bufferSize); #endif /* According to upstream we should set buffer size first - so make sure it is always at least 4x period size to not get underruns (some systems seem to have issues with only 2 periods) */ periodSize = std::min(periodSize, bufferSize / 4); #if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC) // must be pot for pivos. periodSize = CheckNP2(periodSize); #endif bufferSize = std::min(bufferSize, (snd_pcm_uframes_t)8192); periodSize = bufferSize / ALSA_PERIODS; periods = ALSA_PERIODS; CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Req: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize); snd_pcm_hw_params_t *hw_params_copy; snd_pcm_hw_params_alloca(&hw_params_copy); snd_pcm_hw_params_copy(hw_params_copy, hw_params); // copy what we have and is already working // Make sure to not initialize too large to not cause underruns snd_pcm_uframes_t periodSizeMax = bufferSize / 3; if(snd_pcm_hw_params_set_period_size_max(m_pcm, hw_params_copy, &periodSizeMax, NULL) != 0) { snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: Failed to limit periodSize to %lu", periodSizeMax); } // first trying bufferSize, PeriodSize // for more info see here: // http://mailman.alsa-project.org/pipermail/alsa-devel/2009-September/021069.html // the last three tries are done as within pulseaudio // backup periodSize and bufferSize first. Restore them after every failed try snd_pcm_uframes_t periodSizeTemp, bufferSizeTemp; periodSizeTemp = periodSize; bufferSizeTemp = bufferSize; if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0 || snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { bufferSize = bufferSizeTemp; periodSize = periodSizeTemp; // retry with PeriodSize, bufferSize snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy if (snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0 || snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { // try only periodSize periodSize = periodSizeTemp; snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy if(snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { // try only BufferSize bufferSize = bufferSizeTemp; snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restory working copy if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0) { // set default that Alsa would choose CLog::Log(LOGWARNING, "CAESinkAlsa::IntializeHW - Using default alsa values - set failed"); if (snd_pcm_hw_params(m_pcm, hw_params) != 0) { CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Could not init a valid sink"); return false; } } } // reread values when alsa default was kept snd_pcm_get_params(m_pcm, &bufferSize, &periodSize); } } CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, bufferSize %lu", periodSize, bufferSize); /* set the format parameters */ outconfig.sampleRate = sampleRate; outconfig.periodSize = periodSize; outconfig.frameSize = snd_pcm_frames_to_bytes(m_pcm, 1); m_bufferSize = (unsigned int)bufferSize; m_timeout = std::ceil((double)(bufferSize * 1000) / (double)sampleRate); CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Setting timeout to %d ms", m_timeout); return true; }
void info(char *dev_name, snd_pcm_stream_t stream) { snd_pcm_hw_params_t *hw_params; int err; snd_pcm_t *handle; unsigned int max; unsigned int min; unsigned int val; unsigned int dir; snd_pcm_uframes_t frames; if ((err = snd_pcm_open (&handle, dev_name, stream, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", dev_name, snd_strerror (err)); return; } if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_get_channels_max(hw_params, &max)) < 0) { fprintf (stderr, "cannot (%s)\n", snd_strerror (err)); exit (1); } printf("max channels %d\n", max); if ((err = snd_pcm_hw_params_get_channels_min(hw_params, &min)) < 0) { fprintf (stderr, "cannot get channel info (%s)\n", snd_strerror (err)); exit (1); } printf("min channels %d\n", min); /* if ((err = snd_pcm_hw_params_get_sbits(hw_params)) < 0) { fprintf (stderr, "cannot get bits info (%s)\n", snd_strerror (err)); exit (1); } printf("bits %d\n", err); */ if ((err = snd_pcm_hw_params_get_rate_min(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min rate (%s)\n", snd_strerror (err)); exit (1); } printf("min rate %d hz\n", val); if ((err = snd_pcm_hw_params_get_rate_max(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get max rate (%s)\n", snd_strerror (err)); exit (1); } printf("max rate %d hz\n", val); if ((err = snd_pcm_hw_params_get_period_time_min(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min period time (%s)\n", snd_strerror (err)); exit (1); } printf("min period time %d usecs\n", val); if ((err = snd_pcm_hw_params_get_period_time_max(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get max period time (%s)\n", snd_strerror (err)); exit (1); } printf("max period time %d usecs\n", val); if ((err = snd_pcm_hw_params_get_period_size_min(hw_params, &frames, &dir)) < 0) { fprintf (stderr, "cannot get min period size (%s)\n", snd_strerror (err)); exit (1); } printf("min period size in frames %d\n", frames); if ((err = snd_pcm_hw_params_get_period_size_max(hw_params, &frames, &dir)) < 0) { fprintf (stderr, "cannot get max period size (%s)\n", snd_strerror (err)); exit (1); } printf("max period size in frames %d\n", frames); if ((err = snd_pcm_hw_params_get_periods_min(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min periods (%s)\n", snd_strerror (err)); exit (1); } printf("min periods per buffer %d\n", val); if ((err = snd_pcm_hw_params_get_periods_max(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min periods (%s)\n", snd_strerror (err)); exit (1); } printf("max periods per buffer %d\n", val); if ((err = snd_pcm_hw_params_get_buffer_time_min(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min buffer time (%s)\n", snd_strerror (err)); exit (1); } printf("min buffer time %d usecs\n", val); if ((err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get max buffer time (%s)\n", snd_strerror (err)); exit (1); } printf("max buffer time %d usecs\n", val); if ((err = snd_pcm_hw_params_get_buffer_size_min(hw_params, &frames)) < 0) { fprintf (stderr, "cannot get min buffer size (%s)\n", snd_strerror (err)); exit (1); } printf("min buffer size in frames %d\n", frames); if ((err = snd_pcm_hw_params_get_buffer_size_max(hw_params, &frames)) < 0) { fprintf (stderr, "cannot get max buffer size (%s)\n", snd_strerror (err)); exit (1); } printf("max buffer size in frames %d\n", frames); }
int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int *bufsize) { int err, last_bufsize = *bufsize; snd_pcm_hw_params_t *pt_params, *ct_params; /* templates with rate, format and channels */ snd_pcm_hw_params_t *p_params, *c_params; snd_pcm_sw_params_t *p_swparams, *c_swparams; snd_pcm_uframes_t p_size, c_size, p_psize, c_psize; unsigned int p_time, c_time; unsigned int val; snd_pcm_hw_params_alloca(&p_params); snd_pcm_hw_params_alloca(&c_params); snd_pcm_hw_params_alloca(&pt_params); snd_pcm_hw_params_alloca(&ct_params); snd_pcm_sw_params_alloca(&p_swparams); snd_pcm_sw_params_alloca(&c_swparams); if ((err = setparams_stream(phandle, pt_params, "playback")) < 0) { printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err)); exit(0); } if ((err = setparams_stream(chandle, ct_params, "capture")) < 0) { printf("Unable to set parameters for capture stream: %s\n", snd_strerror(err)); exit(0); } if (buffer_size > 0) { *bufsize = buffer_size; goto __set_it; } __again: if (buffer_size > 0) return -1; if (last_bufsize == *bufsize) *bufsize += 4; last_bufsize = *bufsize; if (*bufsize > latency_max) return -1; __set_it: if ((err = setparams_bufsize(phandle, p_params, pt_params, *bufsize, "playback")) < 0) { printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); exit(0); } if ((err = setparams_bufsize(chandle, c_params, ct_params, *bufsize, "capture")) < 0) { printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); exit(0); } snd_pcm_hw_params_get_period_size(p_params, &p_psize, NULL); if (p_psize > (unsigned int)*bufsize) *bufsize = p_psize; snd_pcm_hw_params_get_period_size(c_params, &c_psize, NULL); if (c_psize > (unsigned int)*bufsize) *bufsize = c_psize; snd_pcm_hw_params_get_period_time(p_params, &p_time, NULL); snd_pcm_hw_params_get_period_time(c_params, &c_time, NULL); if (p_time != c_time) goto __again; snd_pcm_hw_params_get_buffer_size(p_params, &p_size); if (p_psize * 2 < p_size) { snd_pcm_hw_params_get_periods_min(p_params, &val, NULL); if (val > 2) { printf("playback device does not support 2 periods per buffer\n"); exit(0); } goto __again; } snd_pcm_hw_params_get_buffer_size(c_params, &c_size); if (c_psize * 2 < c_size) { snd_pcm_hw_params_get_periods_min(c_params, &val, NULL); if (val > 2 ) { printf("capture device does not support 2 periods per buffer\n"); exit(0); } goto __again; } if ((err = setparams_set(phandle, p_params, p_swparams, "playback")) < 0) { printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); exit(0); } if ((err = setparams_set(chandle, c_params, c_swparams, "capture")) < 0) { printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); exit(0); } if ((err = snd_pcm_prepare(phandle)) < 0) { printf("Prepare error: %s\n", snd_strerror(err)); exit(0); } snd_pcm_dump(phandle, output); snd_pcm_dump(chandle, output); fflush(stdout); return 0; }
int VoiceStreamer::setparams_c(snd_pcm_t *chandle, int *bufsize) { int err, last_bufsize = *bufsize; snd_pcm_hw_params_t *ct_params; // templates w/ rate, format and channels snd_pcm_hw_params_t *c_params; snd_pcm_sw_params_t *c_swparams; snd_pcm_uframes_t c_size, c_psize; unsigned int val; snd_pcm_hw_params_alloca(&c_params); snd_pcm_hw_params_alloca(&ct_params); snd_pcm_sw_params_alloca(&c_swparams); if((err = setparams_stream(chandle, ct_params, "capture")) < 0) { printf("Unable to set parameters for capture stream: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } bool again = true; if (buffer_size > 0) { *bufsize = buffer_size; again = false; } for (;; again = true) { if (again) { if (buffer_size > 0) return -1; if (last_bufsize == *bufsize) *bufsize +=4; last_bufsize = *bufsize; if (*bufsize > latency_max) return -1; } if ((err = setparams_bufsize(chandle, c_params, ct_params, *bufsize, "capture")) < 0) { printf("Unable to set sw parameters for capture stream: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } snd_pcm_hw_params_get_period_size(c_params, &c_psize, NULL); if (c_psize > (unsigned int) *bufsize) *bufsize = c_psize; snd_pcm_hw_params_get_buffer_size(c_params, &c_size); if (c_psize*4 < c_size) { snd_pcm_hw_params_get_periods_min(c_params, &val, NULL); if (val > 4) { printf("Capture device does not support 4 periods per buffer\n"); exit(EXIT_FAILURE); } continue; } break; } if ((err = setparams_set(chandle, c_params, c_swparams, "capture")) < 0) { printf("Unable to set sw parameters for capture stream: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } fflush(stdout); return 0; }
int VoiceStreamer::setparams_p(snd_pcm_t *phandle, int *bufsize) { int err, last_bufsize = *bufsize; snd_pcm_hw_params_t *pt_params; snd_pcm_hw_params_t *p_params; snd_pcm_sw_params_t *p_swparams; snd_pcm_uframes_t p_size, p_psize; unsigned int val; snd_pcm_hw_params_alloca(&p_params); snd_pcm_hw_params_alloca(&pt_params); snd_pcm_sw_params_alloca(&p_swparams); if ((err = setparams_stream(phandle, pt_params, "playback")) < 0) { printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } bool again = true; if (buffer_size > 0) { *bufsize = buffer_size; again = false; } for (;; again = true) { if (again) { if (buffer_size > 0) return -1; if (last_bufsize == *bufsize) *bufsize +=4; last_bufsize = *bufsize; if (*bufsize > latency_max) return -1; } if ((err = setparams_bufsize(phandle, p_params, pt_params, *bufsize, "playback")) < 0) { printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } snd_pcm_hw_params_get_period_size(p_params, &p_psize, NULL); if (p_psize > (unsigned int) *bufsize) *bufsize = p_psize; snd_pcm_hw_params_get_buffer_size(p_params, &p_size); if (p_psize*4 < p_size) { snd_pcm_hw_params_get_periods_min(p_params, &val, NULL); if (val > 4) { printf("Playback device does not support 4 periods per buffer\n"); exit(EXIT_FAILURE); } continue; } break; } if ((err = setparams_set(phandle, p_params, p_swparams, "playback")) < 0) { printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } fflush(stdout); return 0; }
bool S9xAlsaSoundDriver::open_device() { int err; unsigned int periods = 8; unsigned int buffer_size = gui_config->sound_buffer_size * 1000; snd_pcm_sw_params_t *sw_params; snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t alsa_buffer_size, alsa_period_size; unsigned int min = 0; unsigned int max = 0; printf("ALSA sound driver initializing...\n"); printf(" --> (Device: default)...\n"); err = snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (err < 0) { goto fail; } printf(" --> (16-bit Stereo, %dhz, %d ms)...\n", Settings.SoundPlaybackRate, gui_config->sound_buffer_size); snd_pcm_hw_params_alloca(&hw_params); snd_pcm_hw_params_any(pcm, hw_params); snd_pcm_hw_params_set_format(pcm, hw_params, SND_PCM_FORMAT_S16); snd_pcm_hw_params_set_access(pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_rate_resample(pcm, hw_params, 0); snd_pcm_hw_params_set_channels(pcm, hw_params, 2); snd_pcm_hw_params_get_rate_min(hw_params, &min, NULL); snd_pcm_hw_params_get_rate_max(hw_params, &max, NULL); printf(" --> Available rates: %d to %d\n", min, max); if (Settings.SoundPlaybackRate > max && Settings.SoundPlaybackRate < min) { printf(" Rate %d not available. Using %d instead.\n", Settings.SoundPlaybackRate, max); Settings.SoundPlaybackRate = max; } snd_pcm_hw_params_set_rate_near(pcm, hw_params, &Settings.SoundPlaybackRate, NULL); snd_pcm_hw_params_get_buffer_time_min(hw_params, &min, NULL); snd_pcm_hw_params_get_buffer_time_max(hw_params, &max, NULL); printf(" --> Available buffer sizes: %dms to %dms\n", min / 1000, max / 1000); if (buffer_size < min && buffer_size > max) { printf(" Buffer size %dms not available. Using %d instead.\n", buffer_size / 1000, (min + max) / 2000); buffer_size = (min + max) / 2; } snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_size, NULL); snd_pcm_hw_params_get_periods_min(hw_params, &min, NULL); snd_pcm_hw_params_get_periods_max(hw_params, &max, NULL); printf(" --> Period ranges: %d to %d blocks\n", min, max); if (periods > max) { periods = max; } snd_pcm_hw_params_set_periods_near(pcm, hw_params, &periods, NULL); if ((err = snd_pcm_hw_params(pcm, hw_params)) < 0) { printf(" Hardware parameter set failed.\n"); goto close_fail; } snd_pcm_sw_params_alloca(&sw_params); snd_pcm_sw_params_current(pcm, sw_params); snd_pcm_get_params(pcm, &alsa_buffer_size, &alsa_period_size); /* Don't start until we're [nearly] full */ snd_pcm_sw_params_set_start_threshold(pcm, sw_params, (alsa_buffer_size / 2)); err = snd_pcm_sw_params(pcm, sw_params); output_buffer_size = snd_pcm_frames_to_bytes(pcm, alsa_buffer_size); if (err < 0) { printf(" Software parameter set failed.\n"); goto close_fail; } printf("OK\n"); S9xSetSamplesAvailableCallback(alsa_samples_available, this); return true; close_fail: snd_pcm_drain(pcm); snd_pcm_close(pcm); pcm = NULL; fail: printf("Failed: %s\n", snd_strerror(err)); return false; }