Example #1
0
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;
    }
Example #3
0
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 (&params);

    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;
    }
}
Example #4
0
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;
}
Example #5
0
/* ------- 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;
}
Example #6
0
static int
set_hwparams (GstAlsaSrc * alsa)
{
  guint rrate;
  gint err;
  snd_pcm_hw_params_t *params;

  snd_pcm_hw_params_malloc (&params);

  /* 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);
}
Example #9
0
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;
}
Example #10
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;
}
Example #11
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;

}
Example #12
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;
}