Example #1
0
static int setparams_periods(snd_pcm_t *handle,
                             snd_pcm_hw_params_t *params,
                             unsigned int *usecs,
                             unsigned int *count,
                             const char *id)
{
    int err;

    err = snd_pcm_hw_params_set_period_time_near(handle, params, usecs, 0);
    if (err < 0) {
        fprintf(error_fp, "alsa: Unable to set period time %u for %s: %s\n",
                *usecs, id, snd_strerror(err));
        return err;
    }

    err = snd_pcm_hw_params_set_periods_near(handle, params, count, 0);
    if (err < 0) {
        fprintf(error_fp, "alsa: Unable to set %u periods for %s: %s\n",
                *count, id, snd_strerror(err));
        return err;
    }

    if (verbose)
        fprintf(error_fp, "alsa: %s period set to %u periods of %u time\n",
                id, *count, *usecs);

    return 0;
}
Example #2
0
static
int set_hwparams(snd_pcm_t *handle,
                 snd_pcm_hw_params_t *params,
                 snd_pcm_access_t access)
{
    int err, dir;

    /* choose all parameters */
    err = snd_pcm_hw_params_any(handle,params);
    if (err < 0) {
        printf("Access type not available for playback: %s\n", snd_strerror(err));
        return err;
    }
    /* set the sample format */
    err = snd_pcm_hw_params_set_format(handle, params, alsa_format);
    if (err < 0) {
        printf("Sample format not available for playback: %s\n", snd_strerror(err));
        return err;
    }
    /* set the count of channels */
    err = snd_pcm_hw_params_set_channels(handle, params, channels);
    if (err < 0) {
        printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
        return err;
    }
    /* set the stream rate */
    err = snd_pcm_hw_params_set_rate_near(handle, params, rate, 0);
    if (err < 0) {
        printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
        return err;
    }
    if (err != rate) {
        printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
        return -EINVAL;
    }
    /* set buffer time */
    err = snd_pcm_hw_params_set_buffer_time_near(handle, params, buffer_time, &dir);
    if (err < 0) {
        printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
        return err;
    }
    buffer_size = snd_pcm_hw_params_get_buffer_size(params);
    /* set period time */
    err = snd_pcm_hw_params_set_period_time_near(handle, params, period_time, &dir);
    if (err < 0) {
        printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
        return err;
    }
    period_size = snd_pcm_hw_params_get_period_size(params, &dir);
    /* write the parameters to device */
    err = snd_pcm_hw_params(handle, params);
    if (err < 0) {
        printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
        return err;
    }
    return 0;
}
Example #3
0
static bool set_snd_pcm_hw_params(snd_pcm_t *snd, snd_pcm_hw_params_t *params, snd_pcm_format_t fmt, unsigned &channels, unsigned &sample_rate, unsigned &delay_us)
{
	const bool ok = !snd_pcm_hw_params_set_access(snd, params, SND_PCM_ACCESS_RW_INTERLEAVED) && !snd_pcm_hw_params_set_format(snd, params, fmt) && !snd_pcm_hw_params_set_channels_near(snd, params, &channels) && !snd_pcm_hw_params_set_rate_near(snd, params, &sample_rate, NULL);
	if (ok)
	{
		unsigned period_us = delay_us >> 2;
		return (!snd_pcm_hw_params_set_buffer_time_near(snd, params, &delay_us, NULL) && !snd_pcm_hw_params_set_period_time_near(snd, params, &period_us, NULL)) || (!snd_pcm_hw_params_set_period_time_near(snd, params, &period_us, NULL) && !snd_pcm_hw_params_set_buffer_time_near(snd, params, &delay_us, NULL));
	}
	return false;
}
Example #4
0
static void set_params(void)
{
	hwparams.format=SND_PCM_FORMAT_S16_LE;
        hwparams.channels=2;
        hwparams.rate=44100;

	snd_pcm_hw_params_t *params;
	snd_pcm_sw_params_t *swparams;

        snd_pcm_hw_params_alloca(&params);
	snd_pcm_sw_params_alloca(&swparams);	

	snd_pcm_hw_params_any(handle, params);
	snd_pcm_hw_params_set_format(handle, params, hwparams.format);
	snd_pcm_hw_params_set_channels(handle, params, hwparams.channels);
	snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0);

	buffer_time=0;
	snd_pcm_hw_params_get_buffer_time_max(params,&buffer_time, 0);

	period_time=125000;
	snd_pcm_hw_params_set_period_time_near(handle, params,&period_time, 0);

	buffer_time = 500000;
	snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0);
	
	/*monotonic = */snd_pcm_hw_params_is_monotonic(params);
        /*can_pause = */snd_pcm_hw_params_can_pause(params);

	
	printf("sizeof(params) : %d\n",sizeof(params));

        snd_pcm_hw_params(handle, params);

        snd_pcm_uframes_t buffer_size;
	snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);

	size_t n=chunk_size;

	snd_pcm_sw_params_set_avail_min(handle, swparams, n);


	snd_pcm_uframes_t start_threshold, stop_threshold;	
	start_threshold=22050;
	snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
	stop_threshold=22050;
	snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
	
	snd_pcm_format_physical_width(hwparams.format);
	
}
static int init(struct xmp_context *ctx)
{
	snd_pcm_hw_params_t *hwparams;
	int ret;
	char *token, **parm;
	unsigned int channels, rate;
	unsigned int btime = 2000000;	/* 2s */
	unsigned int ptime = 100000;	/* 100ms */
	char *card_name = "default";
	struct xmp_options *o = &ctx->o;

	parm_init();  
	chkparm1("buffer", btime = 1000 * strtoul(token, NULL, 0));
	chkparm1("period", btime = 1000 * strtoul(token, NULL, 0));
	chkparm1("card", card_name = token);
	parm_end();

	if ((ret = snd_pcm_open(&pcm_handle, card_name,
		SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
		fprintf(stderr, "Unable to initialize ALSA pcm device: %s\n",
					snd_strerror(ret));
		return XMP_ERR_DINIT;
	}

	channels = (o->outfmt & XMP_FMT_MONO) ? 1 : 2;
	rate = o->freq;

	snd_pcm_hw_params_alloca(&hwparams);
	snd_pcm_hw_params_any(pcm_handle, hwparams);
	snd_pcm_hw_params_set_access(pcm_handle, hwparams,
		SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(pcm_handle, hwparams, to_fmt(o));
	snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0);
	snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &channels);
	snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &btime, 0);
	snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &ptime, 0);
	snd_pcm_nonblock(pcm_handle, 0);
	
	if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
		fprintf(stderr, "Unable to set ALSA output parameters: %s\n",
					snd_strerror(ret));
		return XMP_ERR_DINIT;
	}

	if (prepare_driver() < 0)
		return XMP_ERR_DINIT;
  
	o->freq = rate;

	return xmp_smix_on(ctx);
}
Example #6
0
static int alsa_set_hwparams()
{
	snd_pcm_hw_params_t *hwp;
	snd_pcm_sw_params_t *swp;
	int dir = 1;
	unsigned period_time;
	snd_pcm_uframes_t buffer_size, period_size;

	snd_pcm_hw_params_alloca(&hwp);
	snd_pcm_sw_params_alloca(&swp);

	// ALSA bug? If we request 44100 Hz, it rounds the value up to 48000...
	alsa_hw.rate--;

	if (alsa_error("hw_params_any", snd_pcm_hw_params_any(alsa_hw.handle, hwp))
	    || alsa_error("hw_params_set_format", snd_pcm_hw_params_set_format(alsa_hw.handle, hwp, alsa_hw.format))
	    || alsa_error("hw_params_set_channels",
			  snd_pcm_hw_params_set_channels(alsa_hw.handle, hwp, alsa_hw.num_channels))
	    || alsa_error("hw_params_set_rate_near",
			  snd_pcm_hw_params_set_rate_near(alsa_hw.handle, hwp, &alsa_hw.rate, &dir))
	    || alsa_error("hw_params_set_access",
			  snd_pcm_hw_params_set_access(alsa_hw.handle, hwp, SND_PCM_ACCESS_RW_INTERLEAVED))
	    || alsa_error("hw_params_set_buffer_time_near",
			  snd_pcm_hw_params_set_buffer_time_near(alsa_hw.handle, hwp, &alsa_hw.buffer_time, 0)))
		return -1;

	/* How often to call our SIGIO handler (~40Hz) */
	period_time = alsa_hw.buffer_time / 4;
	if (alsa_error
	    ("hw_params_set_period_time_near",
	     snd_pcm_hw_params_set_period_time_near(alsa_hw.handle, hwp, &period_time, &dir))
	    || alsa_error("hw_params_get_buffer_size", snd_pcm_hw_params_get_buffer_size(hwp, &buffer_size))
	    || alsa_error("hw_params_get_period_size", snd_pcm_hw_params_get_period_size(hwp, &period_size, 0))
	    || alsa_error("hw_params", snd_pcm_hw_params(alsa_hw.handle, hwp)))
		return -1;

	snd_pcm_sw_params_current(alsa_hw.handle, swp);
	if (alsa_error
	    ("sw_params_set_start_threshold", snd_pcm_sw_params_set_start_threshold(alsa_hw.handle, swp, period_size))
	    || alsa_error("sw_params_set_avail_min", snd_pcm_sw_params_set_avail_min(alsa_hw.handle, swp, period_size))
	    || alsa_error("sw_params", snd_pcm_sw_params(alsa_hw.handle, swp)))
		return -1;

	return 0;
}
Example #7
0
static int Open (vlc_object_t *obj)
{
    demux_t *demux = (demux_t *)obj;
    demux_sys_t *sys = vlc_obj_malloc(obj, sizeof (*sys));
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    /* Open the device */
    const char *device = demux->psz_location;
    if (device == NULL || !device[0])
        device = "default";

    const int mode = SND_PCM_NONBLOCK
                 /*| SND_PCM_NO_AUTO_RESAMPLE*/
                   | SND_PCM_NO_AUTO_CHANNELS
                 /*| SND_PCM_NO_AUTO_FORMAT*/;
    snd_pcm_t *pcm;
    int val = snd_pcm_open (&pcm, device, SND_PCM_STREAM_CAPTURE, mode);
    if (val != 0)
    {
        msg_Err (demux, "cannot open ALSA device \"%s\": %s", device,
                 snd_strerror (val));
        return VLC_EGENERIC;
    }
    sys->pcm = pcm;
    msg_Dbg (demux, "using ALSA device: %s", device);
    DumpDevice (VLC_OBJECT(demux), pcm);

    /* Negotiate capture parameters */
    snd_pcm_hw_params_t *hw;
    es_format_t fmt;
    unsigned param;
    int dir;

    snd_pcm_hw_params_alloca (&hw);
    snd_pcm_hw_params_any (pcm, hw);
    Dump (demux, "initial hardware setup:\n", snd_pcm_hw_params_dump, hw);

    val = snd_pcm_hw_params_set_rate_resample (pcm, hw, 0);
    if (val)
    {
        msg_Err (demux, "cannot disable resampling: %s", snd_strerror (val));
        goto error;
    }

    val = snd_pcm_hw_params_set_access (pcm, hw,
                                        SND_PCM_ACCESS_RW_INTERLEAVED);
    if (val)
    {
        msg_Err (demux, "cannot set access mode: %s", snd_strerror (val));
        goto error;
    }

    snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
    for (size_t i = 0; i < sizeof (choices) / sizeof (choices[0]); i++)
        if (snd_pcm_hw_params_test_format (pcm, hw, choices[i]) == 0)
        {
            val = snd_pcm_hw_params_set_format (pcm, hw, choices[i]);
            if (val)
            {
                msg_Err (demux, "cannot set sample format: %s",
                         snd_strerror (val));
                goto error;
            }
            format = choices[i];
            break;
        }

    if (format == SND_PCM_FORMAT_UNKNOWN)
    {
        msg_Err (demux, "no supported sample format");
        goto error;
    }

    assert ((size_t)format < (sizeof (formats) / sizeof (formats[0])));
    es_format_Init (&fmt, AUDIO_ES, formats[format]);
    fmt.audio.i_format = fmt.i_codec;

    param = 1 + var_InheritBool (demux, "alsa-stereo");
    val = snd_pcm_hw_params_set_channels_max (pcm, hw, &param);
    if (val)
    {
        msg_Err (demux, "cannot restrict channels count: %s",
                 snd_strerror (val));
        goto error;
    }
    val = snd_pcm_hw_params_set_channels_last (pcm, hw, &param);
    if (val)
    {
        msg_Err (demux, "cannot set channels count: %s", snd_strerror (val));
        goto error;
    }
    assert (param > 0);
    assert (param < (sizeof (channel_maps) / sizeof (channel_maps[0])));
    fmt.audio.i_channels = param;
    fmt.audio.i_physical_channels = channel_maps[param - 1];

    param = var_InheritInteger (demux, "alsa-samplerate");
    val = snd_pcm_hw_params_set_rate_max (pcm, hw, &param, NULL);
    if (val)
    {
        msg_Err (demux, "cannot restrict rate to %u Hz or less: %s", 192000,
                 snd_strerror (val));
        goto error;
    }
    val = snd_pcm_hw_params_set_rate_last (pcm, hw, &param, &dir);
    if (val)
    {
        msg_Err (demux, "cannot set sample rate: %s", snd_strerror (val));
        goto error;
    }
    if (dir)
        msg_Warn (demux, "sample rate is not integral");
    fmt.audio.i_rate = param;
    sys->rate = param;

    sys->start = mdate ();
    sys->caching = INT64_C(1000) * var_InheritInteger (demux, "live-caching");
    param = sys->caching;
    val = snd_pcm_hw_params_set_buffer_time_near (pcm, hw, &param, NULL);
    if (val)
    {
        msg_Err (demux, "cannot set buffer duration: %s", snd_strerror (val));
        goto error;
    }

    param /= 4;
    val = snd_pcm_hw_params_set_period_time_near (pcm, hw, &param, NULL);
    if (val)
    {
        msg_Err (demux, "cannot set period: %s", snd_strerror (val));
        goto error;
    }

    val = snd_pcm_hw_params_get_period_size (hw, &sys->period_size, &dir);
    if (val)
    {
        msg_Err (demux, "cannot get period size: %s", snd_strerror (val));
        goto error;
    }
    if (dir > 0)
        sys->period_size++;

    /* Commit hardware parameters */
    val = snd_pcm_hw_params (pcm, hw);
    if (val)
    {
        msg_Err (demux, "cannot commit hardware parameters: %s",
                 snd_strerror (val));
        goto error;
    }
    Dump (demux, "final HW setup:\n", snd_pcm_hw_params_dump, hw);

    /* Kick recording */
    aout_FormatPrepare (&fmt.audio);
    sys->es = es_out_Add (demux->out, &fmt);
    demux->p_sys = sys;

    if (vlc_clone (&sys->thread, Thread, demux, VLC_THREAD_PRIORITY_INPUT))
    {
        es_out_Del (demux->out, sys->es);
        goto error;
    }

    demux->pf_demux = NULL;
    demux->pf_control = Control;
    return VLC_SUCCESS;
error:
    snd_pcm_close (pcm);
    return VLC_EGENERIC;
}
static int drvHostALSAAudioOpen(bool fIn,
                                PALSAAUDIOSTREAMCFG pCfgReq,
                                PALSAAUDIOSTREAMCFG pCfgObt,
                                snd_pcm_t **pphPCM)
{
    snd_pcm_t *phPCM = NULL;
    int rc;

    unsigned int cChannels = pCfgReq->nchannels;
    unsigned int uFreq = pCfgReq->freq;
    snd_pcm_uframes_t obt_buffer_size;

    do
    {
        const char *pszDev = fIn ? s_ALSAConf.pcm_name_in : s_ALSAConf.pcm_name_out;
        if (!pszDev)
        {
            LogRel(("ALSA: Invalid or no %s device name set\n",
                    fIn ? "input" : "output"));
            rc = VERR_INVALID_PARAMETER;
            break;
        }

        int err = snd_pcm_open(&phPCM, pszDev,
                               fIn ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
                               SND_PCM_NONBLOCK);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to open \"%s\" as %s: %s\n", pszDev,
                    fIn ? "ADC" : "DAC", snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        snd_pcm_hw_params_t *pHWParms;
        snd_pcm_hw_params_alloca(&pHWParms); /** @todo Check for successful allocation? */
        err = snd_pcm_hw_params_any(phPCM, pHWParms);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to initialize hardware parameters: %s\n",
                    snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_set_access(phPCM, pHWParms,
                                           SND_PCM_ACCESS_RW_INTERLEAVED);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to set access type: %s\n", snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_set_format(phPCM, pHWParms, pCfgReq->fmt);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to set audio format to %d: %s\n",
                    pCfgReq->fmt, snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_set_rate_near(phPCM, pHWParms, &uFreq, 0);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to set frequency to %dHz: %s\n",
                    pCfgReq->freq, snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_set_channels_near(phPCM, pHWParms, &cChannels);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to set number of channels to %d\n", pCfgReq->nchannels));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        if (   cChannels != 1
            && cChannels != 2)
        {
            LogRel(("ALSA: Number of audio channels (%u) not supported\n", cChannels));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        unsigned int period_size = pCfgReq->period_size;
        unsigned int buffer_size = pCfgReq->buffer_size;

        if (   !((fIn && s_ALSAConf.size_in_usec_in)
            ||  (!fIn && s_ALSAConf.size_in_usec_out)))
        {
            if (!buffer_size)
            {
                buffer_size = DEFAULT_BUFFER_SIZE;
                period_size = DEFAULT_PERIOD_SIZE;
            }
        }

        if (buffer_size)
        {
            if (   ( fIn && s_ALSAConf.size_in_usec_in)
                || (!fIn && s_ALSAConf.size_in_usec_out))
            {
                if (period_size)
                {
                    err = snd_pcm_hw_params_set_period_time_near(phPCM, pHWParms,
                                                                 &period_size, 0);
                    if (err < 0)
                    {
                        LogRel(("ALSA: Failed to set period time %d\n", pCfgReq->period_size));
                        rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                        break;
                    }
                }

                err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pHWParms,
                                                             &buffer_size, 0);
                if (err < 0)
                {
                    LogRel(("ALSA: Failed to set buffer time %d\n", pCfgReq->buffer_size));
                    rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                    break;
                }
            }
            else
            {
                snd_pcm_uframes_t period_size_f = (snd_pcm_uframes_t)period_size;
                snd_pcm_uframes_t buffer_size_f = (snd_pcm_uframes_t)buffer_size;

                snd_pcm_uframes_t minval;

                if (period_size_f)
                {
                    minval = period_size_f;

                    int dir = 0;
                    err = snd_pcm_hw_params_get_period_size_min(pHWParms,
                                                                &minval, &dir);
                    if (err < 0)
                    {
                        LogRel(("ALSA: Could not determine minimal period size\n"));
                        rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                        break;
                    }
                    else
                    {
                        LogFunc(("Minimal period size is: %ld\n", minval));
                        if (period_size_f < minval)
                        {
                            if (   ( fIn && s_ALSAConf.period_size_in_overriden)
                                || (!fIn && s_ALSAConf.period_size_out_overriden))
                            {
                                LogFunc(("Period size %RU32 is less than minimal period size %RU32\n",
                                         period_size_f, minval));
                            }

                            period_size_f = minval;
                        }
                    }

                    err = snd_pcm_hw_params_set_period_size_near(phPCM, pHWParms,
                                                                 &period_size_f, 0);
                    LogFunc(("Period size is: %RU32\n", period_size_f));
                    if (err < 0)
                    {
                        LogRel(("ALSA: Failed to set period size %d (%s)\n",
                                period_size_f, snd_strerror(err)));
                        rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                        break;
                    }
                }

                /* Calculate default buffer size here since it might have been changed
                 * in the _near functions */
                buffer_size_f = 4 * period_size_f;

                minval = buffer_size_f;
                err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval);
                if (err < 0)
                {
                    LogRel(("ALSA: Could not retrieve minimal buffer size\n"));
                    rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                    break;
                }
                else
                {
                    LogFunc(("Minimal buffer size is: %RU32\n", minval));
                    if (buffer_size_f < minval)
                    {
                        if (   ( fIn && s_ALSAConf.buffer_size_in_overriden)
                            || (!fIn && s_ALSAConf.buffer_size_out_overriden))
                        {
                            LogFunc(("Buffer size %RU32 is less than minimal buffer size %RU32\n",
                                     buffer_size_f, minval));
                        }

                        buffer_size_f = minval;
                    }
                }

                err = snd_pcm_hw_params_set_buffer_size_near(phPCM,
                                                             pHWParms, &buffer_size_f);
                LogFunc(("Buffer size is: %RU32\n", buffer_size_f));
                if (err < 0)
                {
                    LogRel(("ALSA: Failed to set buffer size %d: %s\n",
                            buffer_size_f, snd_strerror(err)));
                    rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                    break;
                }
            }
        }
        else
            LogFunc(("Warning: Buffer size is not set\n"));

        err = snd_pcm_hw_params(phPCM, pHWParms);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to apply audio parameters\n"));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to get buffer size\n"));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        snd_pcm_uframes_t obt_period_size;
        int dir = 0;
        err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to get period size\n"));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        LogFunc(("Freq=%dHz, period size=%RU32, buffer size=%RU32\n",
                 pCfgReq->freq, obt_period_size, obt_buffer_size));

        err = snd_pcm_prepare(phPCM);
        if (err < 0)
        {
            LogRel(("ALSA: Could not prepare hPCM %p\n", (void *)phPCM));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        if (   !fIn
            && s_ALSAConf.threshold)
        {
            unsigned uShift;
            rc = drvHostALSAAudioALSAGetShift(pCfgReq->fmt, &uShift);
            if (RT_SUCCESS(rc))
            {
                int bytes_per_sec = uFreq
                    << (cChannels == 2)
                    << uShift;

                snd_pcm_uframes_t threshold
                    = (s_ALSAConf.threshold * bytes_per_sec) / 1000;

                rc = drvHostALSAAudioSetThreshold(phPCM, threshold);
            }
        }
        else
            rc = VINF_SUCCESS;
    }
    while (0);

    if (RT_SUCCESS(rc))
    {
        pCfgObt->fmt       = pCfgReq->fmt;
        pCfgObt->nchannels = cChannels;
        pCfgObt->freq      = uFreq;
        pCfgObt->samples   = obt_buffer_size;

        *pphPCM = phPCM;
    }
    else
        drvHostALSAAudioClose(&phPCM);

    LogFlowFuncLeaveRC(rc);
    return rc;
}
// returns TRUE if successful
int setHWParams(AlsaPcmInfo* info,
                float sampleRate,
                int channels,
                int bufferSizeInFrames,
                snd_pcm_format_t format) {
    unsigned int rrate;
    int ret, dir, periods, periodTime;
    snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames;

    /* choose all parameters */
    ret = snd_pcm_hw_params_any(info->handle, info->hwParams);
    if (ret < 0) {
        ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret));
        return FALSE;
    }
    /* set the interleaved read/write format */
    ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (ret < 0) {
        ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret));
        return FALSE;
    }
    /* set the sample format */
    ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format);
    if (ret < 0) {
        ERROR1("Sample format not available: %s\n", snd_strerror(ret));
        return FALSE;
    }
    /* set the count of channels */
    ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels);
    if (ret < 0) {
        ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret));
        return FALSE;
    }
    /* set the stream rate */
    rrate = (int) (sampleRate + 0.5f);
#ifdef ALSA_PCM_NEW_HW_PARAMS_API
    dir = 0;
    ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir);
#else
    ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, rrate, 0);
#endif
    if (ret < 0) {
        ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret));
        return FALSE;
    }
    if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) {
        ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate);
        return FALSE;
    }
    /* set the buffer time */
#ifdef ALSA_PCM_NEW_HW_PARAMS_API

    ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames);
#else
    ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, alsaBufferSizeInFrames);
#endif
    if (ret < 0) {
        ERROR2("Unable to set buffer size to %d frames: %s\n",
               (int) alsaBufferSizeInFrames, snd_strerror(ret));
        return FALSE;
    }
    bufferSizeInFrames = (int) alsaBufferSizeInFrames;
    /* set the period time */
    if (bufferSizeInFrames > 1024) {
        dir = 0;
        periodTime = DEFAULT_PERIOD_TIME;
#ifdef ALSA_PCM_NEW_HW_PARAMS_API
        ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir);
#else
        periodTime = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, periodTime, &dir);
        ret = periodTime;
#endif
        if (ret < 0) {
            ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret));
            return FALSE;
        }
    } else {
        /* set the period count for very small buffer sizes to 2 */
        dir = 0;
        periods = 2;
#ifdef ALSA_PCM_NEW_HW_PARAMS_API
        ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir);
#else
        periods = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, periods, &dir);
        ret = periods;
#endif
        if (ret < 0) {
            ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret));
            return FALSE;
        }
    }
    /* write the parameters to device */
    ret = snd_pcm_hw_params(info->handle, info->hwParams);
    if (ret < 0) {
        ERROR1("Unable to set hw params: %s\n", snd_strerror(ret));
        return FALSE;
    }
    return TRUE;
}
Example #10
0
int
ga_alsa_set_param(struct Xcap_alsa_param *param) {
	snd_pcm_hw_params_t *hwparams = NULL;
	snd_pcm_sw_params_t *swparams = NULL;
	size_t bits_per_sample;
	unsigned int rate;
	unsigned int buffer_time = 500000;	// in the unit of microsecond
	unsigned int period_time = 125000;	// = buffer_time/4;
	int monotonic = 0;
	snd_pcm_uframes_t start_threshold, stop_threshold;
	int err;
	//
	snd_pcm_hw_params_alloca(&hwparams);
	snd_pcm_sw_params_alloca(&swparams);
	if((err = snd_pcm_hw_params_any(param->handle, hwparams)) < 0) {
		ga_error("ALSA: set_param - no configurations available\n");
		return -1;
	}
	if((err = snd_pcm_hw_params_set_access(param->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
		ga_error("ALSA: set_param - access type (interleaved) not available\n");
		return -1;
	}
	if((err = snd_pcm_hw_params_set_format(param->handle, hwparams, param->format)) < 0) {
		ga_error("ALSA: set_param - unsupported sample format.\n");
		return -1;
	}
	if((err = snd_pcm_hw_params_set_channels(param->handle, hwparams, param->channels)) < 0) {
		ga_error("ALSA: set_param - channles count not available\n");
		return -1;
	}
	rate = param->samplerate;
	if((err = snd_pcm_hw_params_set_rate_near(param->handle, hwparams, &rate, 0)) < 0) {
		ga_error("ALSA: set_param - set rate failed.\n");
		return -1;
	}
	if((double)param->samplerate*1.05 < rate || (double)param->samplerate*0.95 > rate) {
		ga_error("ALSA: set_param/warning - inaccurate rate (req=%iHz, got=%iHz)\n", param->samplerate, rate);
	}
	//
	period_time = buffer_time/4;
	if((err = snd_pcm_hw_params_set_period_time_near(param->handle, hwparams, &period_time, 0)) < 0) {
		ga_error("ALSA: set_param - set period time failed.\n");
		return -1;
	}
	if((err = snd_pcm_hw_params_set_buffer_time_near(param->handle, hwparams, &buffer_time, 0)) < 0) {
		ga_error("ALSA: set_param - set buffer time failed.\n");
		return -1;
	}
	//
	monotonic = snd_pcm_hw_params_is_monotonic(hwparams);
	if((err = snd_pcm_hw_params(param->handle, hwparams)) < 0) {
		ga_error("ALSA: set_param - unable to install hw params:");
		snd_pcm_hw_params_dump(hwparams, sndlog);
		return -1;
	}
	snd_pcm_hw_params_get_period_size(hwparams, &param->chunk_size, 0);
	snd_pcm_hw_params_get_buffer_size(hwparams, &param->buffer_size);
	if(param->chunk_size == param->buffer_size) {
		ga_error("ALSA: set_param - cannot use period equal to buffer size (%lu==%lu)\n",
			param->chunk_size, param->buffer_size);
		return -1;
	}
	//
	snd_pcm_sw_params_current(param->handle, swparams);
	err = snd_pcm_sw_params_set_avail_min(param->handle, swparams, param->chunk_size);
	// start_delay = 1 for capture
	start_threshold = (double) param->samplerate * /*start_delay=*/ 1 / 1000000;
	if(start_threshold < 1)				start_threshold = 1;
	if(start_threshold > param->buffer_size)	start_threshold = param->buffer_size;
	if((err = snd_pcm_sw_params_set_start_threshold(param->handle, swparams, start_threshold)) < 0) {
		ga_error("ALSA: set_param - set start threshold failed.\n");
		return -1;
	}
	// stop_delay = 0
	stop_threshold = param->buffer_size;
	if((err = snd_pcm_sw_params_set_stop_threshold(param->handle, swparams, stop_threshold)) < 0) {
		ga_error("ALSA: set_param - set stop threshold failed.\n");
		return -1;
	}
	//
	if(snd_pcm_sw_params(param->handle, swparams) < 0) {
		ga_error("ALSA: set_param - unable to install sw params:");
		snd_pcm_sw_params_dump(swparams, sndlog);
		return -1;
	}

	bits_per_sample = snd_pcm_format_physical_width(param->format);
	if(param->bits_per_sample != bits_per_sample) {
		ga_error("ALSA: set_param - BPS/HW configuration mismatched %d != %d)\n",
			param->bits_per_sample, bits_per_sample);
	}
	param->bits_per_frame = param->bits_per_sample * param->channels;
	param->chunk_bytes = param->chunk_size * param->bits_per_frame / 8;

	return 0;
}
Example #11
0
void
ags_devout_alsa_init(AgsSoundcard *soundcard,
		     GError **error)
{
  AgsDevout *devout;
  
  int rc;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *hwparams;
  unsigned int val;
  snd_pcm_uframes_t frames;
  unsigned int rate;
  unsigned int rrate;
  unsigned int channels;
  snd_pcm_uframes_t size;
  snd_pcm_sframes_t buffer_size;
  snd_pcm_sframes_t period_size;
  snd_pcm_sw_params_t *swparams;
  int period_event = 0;
  int err, dir;

  static unsigned int period_time = 100000;
  static snd_pcm_format_t format = SND_PCM_FORMAT_S16;

  devout = AGS_DEVOUT(soundcard);
  
  /*  */
  devout->flags |= (AGS_DEVOUT_BUFFER3 |
		    AGS_DEVOUT_START_PLAY |
		    AGS_DEVOUT_PLAY |
		    AGS_DEVOUT_NONBLOCKING);

  devout->note_offset = 0;

  memset(devout->buffer[0], 0, devout->dsp_channels * devout->buffer_size * sizeof(signed short));
  memset(devout->buffer[1], 0, devout->dsp_channels * devout->buffer_size * sizeof(signed short));
  memset(devout->buffer[2], 0, devout->dsp_channels * devout->buffer_size * sizeof(signed short));
  memset(devout->buffer[3], 0, devout->dsp_channels * devout->buffer_size * sizeof(signed short));

  /* Open PCM device for playback. */
  if ((err = snd_pcm_open(&handle, devout->out.alsa.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
    printf("Playback open error: %s\n", snd_strerror(err));
    g_set_error(error,
		AGS_DEVOUT_ERROR,
		AGS_DEVOUT_ERROR_LOCKED_SOUNDCARD,
		"unable to open pcm device: %s\n\0",
		snd_strerror(err));
    return;
  }

  snd_pcm_hw_params_alloca(&hwparams);
  snd_pcm_sw_params_alloca(&swparams);

  /* choose all parameters */
  err = snd_pcm_hw_params_any(handle, hwparams);
  if (err < 0) {
    printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
    return;
  }

  /* set hardware resampling */
  err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 1);
  if (err < 0) {
    printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
    return;
  }

  /* set the interleaved read/write format */
  err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err < 0) {
    printf("Access type not available for playback: %s\n", snd_strerror(err));
    return;
  }

  /* set the sample format */
  err = snd_pcm_hw_params_set_format(handle, hwparams, format);
  if (err < 0) {
    printf("Sample format not available for playback: %s\n", snd_strerror(err));
    return;
  }

  /* set the count of channels */
  channels = devout->dsp_channels;
  err = snd_pcm_hw_params_set_channels(handle, hwparams, channels);
  if (err < 0) {
    printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
    return;
  }

  /* set the stream rate */
  rate = devout->samplerate;
  rrate = rate;
  err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rrate, 0);
  if (err < 0) {
    printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
    return;
  }

  if (rrate != rate) {
    printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
    //    exit(-EINVAL);
    return;
  }

  /* set the buffer size */
  size = devout->buffer_size;
  err = snd_pcm_hw_params_set_buffer_size(handle, hwparams, size);
  if (err < 0) {
    printf("Unable to set buffer size %i for playback: %s\n", size, snd_strerror(err));
    return;
  }

  buffer_size = size;

  /* set the period time */
  period_time = MSEC_PER_SEC / devout->samplerate;
  dir = -1;
  err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
  if (err < 0) {
    printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
    return;
  }

  err = snd_pcm_hw_params_get_period_size(hwparams, &size, &dir);
  if (err < 0) {
    printf("Unable to get period size for playback: %s\n", snd_strerror(err));
    return;
  }
  period_size = size;

  /* write the parameters to device */
  err = snd_pcm_hw_params(handle, hwparams);
  if (err < 0) {
    printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
    return;
  }

  /* get the current swparams */
  err = snd_pcm_sw_params_current(handle, swparams);
  if (err < 0) {
    printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
    return;
  }

  /* start the transfer when the buffer is almost full: */
  /* (buffer_size / avail_min) * avail_min */
  err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size);
  if (err < 0) {
    printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
    return;
  }

  /* allow the transfer when at least period_size samples can be processed */
  /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
  err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size);
  if (err < 0) {
    printf("Unable to set avail min for playback: %s\n", snd_strerror(err));
    return;
  }

  /* write the parameters to the playback device */
  err = snd_pcm_sw_params(handle, swparams);
  if (err < 0) {
    printf("Unable to set sw params for playback: %s\n", snd_strerror(err));
    return;
  }

  /*  */
  devout->out.alsa.handle = handle;
  devout->delay_counter = 0.0;
  devout->tic_counter = 0;
}
static int open_alsa_output()
{
    snd_pcm_hw_params_t     *hw;
    snd_pcm_sw_params_t     *sw;
    int err;
    unsigned int alsa_buffer_time;
    unsigned int alsa_period_time;

    qDebug() << "open_alsa_output():   pcmname = " << pcmname;
    if (!pcmname) {
        pcmname = (char*) malloc( 8 );
        strcpy(pcmname,"default\0");
    }

    if ((err = snd_pcm_open (&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
        printf("Error: audio open error: %s\r\n", snd_strerror (-err));
        qDebug() << "Error: audio open error: " << QString::fromLocal8Bit(snd_strerror (-err)) << ",   err = " << err;
        return -1;
    }

    snd_pcm_hw_params_alloca (&hw);

    if ((err = snd_pcm_hw_params_any(pcm, hw)) < 0) {
        printf("ERROR: No configuration available for playback: %s\r\n", snd_strerror(-err));

        return -1;
    }

    if ((err = snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        printf("Cannot set mmap'ed mode: %s.\r\n", snd_strerror(-err));
        return -1;
    }

    if (snd_pcm_hw_params_set_format (pcm, hw, SND_PCM_FORMAT_S16_LE) < 0) {
        printf("ALSA does not support 16bit signed audio for your soundcard\r\n");
        close_alsa_output();
        return -1;
    }

    if (snd_pcm_hw_params_set_channels (pcm, hw, 2) < 0) {
        printf("ALSA does not support stereo for your soundcard\r\n");
        close_alsa_output();
        return -1;
    }

    if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, 0) < 0) {
        printf("ALSA does not support %iHz for your soundcard\r\n",rate);
        close_alsa_output();
        return -1;
    }

    alsa_buffer_time = 500000;
    alsa_period_time = 50000;

    if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hw, &alsa_buffer_time, 0)) < 0)
    {
        printf("Set buffer time failed: %s.\r\n", snd_strerror(-err));
        return -1;
    }

    if ((err = snd_pcm_hw_params_set_period_time_near(pcm, hw, &alsa_period_time, 0)) < 0)
    {
        printf("Set period time failed: %s.\r\n", snd_strerror(-err));
        return -1;
    }

    if (snd_pcm_hw_params(pcm, hw) < 0)
    {
        printf("Unable to install hw params\r\n");
        return -1;
    }

    snd_pcm_sw_params_alloca(&sw);
    snd_pcm_sw_params_current(pcm, sw);
    if (snd_pcm_sw_params(pcm, sw) < 0)
    {
        printf("Unable to install sw params\r\n");
        return -1;
    }

    send_output = write_alsa_output;
    close_output = close_alsa_output;
    if (pcmname != NULL) {
        free (pcmname);
        pcmname = NULL;
    }
    return 0;
}
Example #13
0
/**************************************************************************
 * 				widOpen				[internal]
 */
static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
{
    WINE_WAVEDEV*	        wwi;
    snd_pcm_hw_params_t *       hw_params;
    snd_pcm_sw_params_t *       sw_params;
    snd_pcm_access_t            access;
    snd_pcm_format_t            format;
    unsigned int                rate;
    unsigned int                buffer_time = 500000;
    unsigned int                period_time = 10000;
    snd_pcm_uframes_t           buffer_size;
    snd_pcm_uframes_t           period_size;
    int                         flags;
    snd_pcm_t *                 pcm;
    int                         err;
    int                         dir;
    DWORD                       ret;

    /* JPW TODO - review this code */
    TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
    if (lpDesc == NULL) {
	WARN("Invalid Parameter !\n");
	return MMSYSERR_INVALPARAM;
    }
    if (wDevID >= ALSA_WidNumDevs) {
	TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs);
	return MMSYSERR_BADDEVICEID;
    }

    /* only PCM format is supported so far... */
    if (!ALSA_supportedFormat(lpDesc->lpFormat)) {
	WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
	     lpDesc->lpFormat->nSamplesPerSec);
	return WAVERR_BADFORMAT;
    }

    if (dwFlags & WAVE_FORMAT_QUERY) {
	TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
	     lpDesc->lpFormat->nSamplesPerSec);
	return MMSYSERR_NOERROR;
    }

    wwi = &WInDev[wDevID];

    if (wwi->pcm != NULL) {
        WARN("already allocated\n");
        return MMSYSERR_ALLOCATED;
    }

    wwi->pcm = 0;
    flags = SND_PCM_NONBLOCK;

    if ( (err=snd_pcm_open(&pcm, wwi->pcmname, SND_PCM_STREAM_CAPTURE, flags)) < 0 )
    {
        ERR("Error open: %s\n", snd_strerror(err));
	return MMSYSERR_NOTENABLED;
    }

    wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);

    wwi->waveDesc = *lpDesc;
    ALSA_copyFormat(lpDesc->lpFormat, &wwi->format);

    if (wwi->format.Format.wBitsPerSample == 0) {
	WARN("Resetting zeroed wBitsPerSample\n");
	wwi->format.Format.wBitsPerSample = 8 *
	    (wwi->format.Format.nAvgBytesPerSec /
	     wwi->format.Format.nSamplesPerSec) /
	    wwi->format.Format.nChannels;
    }

    hw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof() );
    sw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof() );

    snd_pcm_hw_params_any(pcm, hw_params);

#define EXIT_ON_ERROR(f,e,txt) do \
{ \
    int err; \
    if ( (err = (f) ) < 0) \
    { \
	WARN(txt ": %s\n", snd_strerror(err)); \
	ret = (e); \
        goto error; \
    } \
} while(0)

    access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
    if ( ( err = snd_pcm_hw_params_set_access(pcm, hw_params, access ) ) < 0) {
        WARN("mmap not available. switching to standard write.\n");
        access = SND_PCM_ACCESS_RW_INTERLEAVED;
	EXIT_ON_ERROR( snd_pcm_hw_params_set_access(pcm, hw_params, access ), MMSYSERR_INVALPARAM, "unable to set access for playback");
	wwi->read = snd_pcm_readi;
    }
    else
	wwi->read = snd_pcm_mmap_readi;

    EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwi->format.Format.nChannels), WAVERR_BADFORMAT, "unable to set required channels");

    if ((wwi->format.Format.wFormatTag == WAVE_FORMAT_PCM) ||
        ((wwi->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
        IsEqualGUID(&wwi->format.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) {
        format = (wwi->format.Format.wBitsPerSample == 8) ? SND_PCM_FORMAT_U8 :
                 (wwi->format.Format.wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE :
                 (wwi->format.Format.wBitsPerSample == 24) ? SND_PCM_FORMAT_S24_3LE :
                 (wwi->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_S32_LE : -1;
    } else if ((wwi->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
        IsEqualGUID(&wwi->format.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){
        format = (wwi->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_FLOAT_LE : -1;
    } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_MULAW) {
        FIXME("unimplemented format: WAVE_FORMAT_MULAW\n");
        ret = WAVERR_BADFORMAT;
        goto error;
    } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_ALAW) {
        FIXME("unimplemented format: WAVE_FORMAT_ALAW\n");
        ret = WAVERR_BADFORMAT;
        goto error;
    } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_ADPCM) {
        FIXME("unimplemented format: WAVE_FORMAT_ADPCM\n");
        ret = WAVERR_BADFORMAT;
        goto error;
    } else {
        ERR("invalid format: %0x04x\n", wwi->format.Format.wFormatTag);
        ret = WAVERR_BADFORMAT;
        goto error;
    }

    EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), WAVERR_BADFORMAT, "unable to set required format");

    rate = wwi->format.Format.nSamplesPerSec;
    dir = 0;
    err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, &dir);
    if (err < 0) {
	WARN("Rate %d Hz not available for playback: %s\n", wwi->format.Format.nSamplesPerSec, snd_strerror(rate));
        ret = WAVERR_BADFORMAT;
        goto error;
    }
    if (!ALSA_NearMatch(rate, wwi->format.Format.nSamplesPerSec)) {
	WARN("Rate doesn't match (requested %d Hz, got %d Hz)\n", wwi->format.Format.nSamplesPerSec, rate);
        ret = WAVERR_BADFORMAT;
        goto error;
    }

    dir=0;
    EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, &dir), MMSYSERR_INVALPARAM, "unable to set buffer time");
    dir=0;
    EXIT_ON_ERROR( snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &period_time, &dir), MMSYSERR_INVALPARAM, "unable to set period time");

    EXIT_ON_ERROR( snd_pcm_hw_params(pcm, hw_params), MMSYSERR_INVALPARAM, "unable to set hw params for playback");

    dir=0;
    err = snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir);
    err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);

    snd_pcm_sw_params_current(pcm, sw_params);
    EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set start threshold");
    EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size");
    EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min");
    EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold");
    EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback");
#undef EXIT_ON_ERROR

    snd_pcm_prepare(pcm);

    if (TRACE_ON(wave))
	ALSA_TraceParameters(hw_params, sw_params, FALSE);

    /* now, we can save all required data for later use... */
    if ( wwi->hw_params )
	snd_pcm_hw_params_free(wwi->hw_params);
    snd_pcm_hw_params_malloc(&(wwi->hw_params));
    snd_pcm_hw_params_copy(wwi->hw_params, hw_params);

    wwi->dwBufferSize = snd_pcm_frames_to_bytes(pcm, buffer_size);
    wwi->lpQueuePtr = wwi->lpPlayPtr = wwi->lpLoopPtr = NULL;
    wwi->pcm = pcm;

    ALSA_InitRingMessage(&wwi->msgRing);

    wwi->dwPeriodSize = snd_pcm_frames_to_bytes(pcm, period_size);
    TRACE("dwPeriodSize=%u\n", wwi->dwPeriodSize);
    TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n",
	  wwi->format.Format.wBitsPerSample, wwi->format.Format.nAvgBytesPerSec,
	  wwi->format.Format.nSamplesPerSec, wwi->format.Format.nChannels,
	  wwi->format.Format.nBlockAlign);

    wwi->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
    wwi->hThread = CreateThread(NULL, 0, widRecorder, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwi->dwThreadID));
    if (wwi->hThread)
        SetThreadPriority(wwi->hThread, THREAD_PRIORITY_TIME_CRITICAL);
    WaitForSingleObject(wwi->hStartUpEvent, INFINITE);
    CloseHandle(wwi->hStartUpEvent);
    wwi->hStartUpEvent = INVALID_HANDLE_VALUE;

    HeapFree( GetProcessHeap(), 0, hw_params );
    HeapFree( GetProcessHeap(), 0, sw_params );
    return widNotifyClient(wwi, WIM_OPEN, 0L, 0L);

error:
    snd_pcm_close(pcm);
    HeapFree( GetProcessHeap(), 0, hw_params );
    HeapFree( GetProcessHeap(), 0, sw_params );
    return ret;
}
Example #14
0
static ALCboolean alsa_reset_playback(ALCdevice *device)
{
    alsa_data *data = (alsa_data*)device->ExtraData;
    snd_pcm_uframes_t periodSizeInFrames;
    unsigned int periodLen, bufferLen;
    snd_pcm_sw_params_t *sp = NULL;
    snd_pcm_hw_params_t *hp = NULL;
    snd_pcm_access_t access;
    snd_pcm_format_t format;
    unsigned int periods;
    unsigned int rate;
    const char *funcerr;
    int allowmmap;
    int err;

    format = -1;
    switch(device->FmtType)
    {
        case DevFmtByte:
            format = SND_PCM_FORMAT_S8;
            break;
        case DevFmtUByte:
            format = SND_PCM_FORMAT_U8;
            break;
        case DevFmtShort:
            format = SND_PCM_FORMAT_S16;
            break;
        case DevFmtUShort:
            format = SND_PCM_FORMAT_U16;
            break;
        case DevFmtInt:
            format = SND_PCM_FORMAT_S32;
            break;
        case DevFmtUInt:
            format = SND_PCM_FORMAT_U32;
            break;
        case DevFmtFloat:
            format = SND_PCM_FORMAT_FLOAT;
            break;
    }

    allowmmap = GetConfigValueBool("alsa", "mmap", 1);
    periods = device->NumUpdates;
    periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
    bufferLen = periodLen * periods;
    rate = device->Frequency;

    snd_pcm_hw_params_malloc(&hp);
#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
    CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp));
    /* set interleaved access */
    if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
    {
        if(periods > 2)
        {
            periods--;
            bufferLen = periodLen * periods;
        }
        CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
    }
    /* test and set format (implicitly sets sample bits) */
    if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0)
    {
        static const struct {
            snd_pcm_format_t format;
            enum DevFmtType fmttype;
        } formatlist[] = {
            { SND_PCM_FORMAT_FLOAT, DevFmtFloat  },
            { SND_PCM_FORMAT_S32,   DevFmtInt    },
            { SND_PCM_FORMAT_U32,   DevFmtUInt   },
            { SND_PCM_FORMAT_S16,   DevFmtShort  },
            { SND_PCM_FORMAT_U16,   DevFmtUShort },
            { SND_PCM_FORMAT_S8,    DevFmtByte   },
            { SND_PCM_FORMAT_U8,    DevFmtUByte  },
        };
        size_t k;

        for(k = 0;k < COUNTOF(formatlist);k++)
        {
            format = formatlist[k].format;
            if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0)
            {
                device->FmtType = formatlist[k].fmttype;
                break;
            }
        }
    }
    CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format));
    /* test and set channels (implicitly sets frame bits) */
    if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
    {
        static const enum DevFmtChannels channellist[] = {
            DevFmtStereo,
            DevFmtQuad,
            DevFmtX51,
            DevFmtX71,
            DevFmtMono,
        };
        size_t k;

        for(k = 0;k < COUNTOF(channellist);k++)
        {
            if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
            {
                device->FmtChans = channellist[k];
                break;
            }
        }
    }
    CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
    /* set rate (implicitly constrains period/buffer parameters) */
    if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0)
        ERR("Failed to disable ALSA resampler\n");
    CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL));
    /* set buffer time (implicitly constrains period/buffer parameters) */
    CHECK(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL));
    /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
    CHECK(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL));
    /* install and prepare hardware configuration */
    CHECK(snd_pcm_hw_params(data->pcmHandle, hp));
    /* retrieve configuration info */
    CHECK(snd_pcm_hw_params_get_access(hp, &access));
    CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL));
    CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL));

    snd_pcm_hw_params_free(hp);
    hp = NULL;
    snd_pcm_sw_params_malloc(&sp);

    CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp));
    CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames));
    CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods));
    CHECK(snd_pcm_sw_params(data->pcmHandle, sp));
#undef CHECK
    snd_pcm_sw_params_free(sp);
    sp = NULL;

    /* Increase periods by one, since the temp buffer counts as an extra
     * period */
    if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
        device->NumUpdates = periods+1;
    else
        device->NumUpdates = periods;
    device->UpdateSize = periodSizeInFrames;
    device->Frequency = rate;

    SetDefaultChannelOrder(device);

    return ALC_TRUE;

error:
    ERR("%s failed: %s\n", funcerr, snd_strerror(err));
    if(hp) snd_pcm_hw_params_free(hp);
    if(sp) snd_pcm_sw_params_free(sp);
    return ALC_FALSE;
}
Example #15
0
static HRESULT SetFormat(IDsDriverBufferImpl *This, LPWAVEFORMATEX pwfx)
{
    snd_pcm_t *pcm = NULL;
    snd_pcm_hw_params_t *hw_params = This->hw_params;
    unsigned int buffer_time = 500000;
    snd_pcm_format_t format = -1;
    snd_pcm_uframes_t psize;
    DWORD rate = pwfx->nSamplesPerSec;
    int err=0;

    switch (pwfx->wBitsPerSample)
    {
        case  8: format = SND_PCM_FORMAT_U8; break;
        case 16: format = SND_PCM_FORMAT_S16_LE; break;
        case 24: format = SND_PCM_FORMAT_S24_3LE; break;
        case 32: format = SND_PCM_FORMAT_S32_LE; break;
        default: FIXME("Unsupported bpp: %d\n", pwfx->wBitsPerSample); return DSERR_GENERIC;
    }

    err = snd_pcm_open(&pcm, WOutDev[This->drv->wDevID].pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
    if (err < 0)
    {
        if (errno != EBUSY || !This->pcm)
        {
            WARN("Cannot open sound device: %s\n", snd_strerror(err));
            return DSERR_GENERIC;
        }
        snd_pcm_drop(This->pcm);
        snd_pcm_close(This->pcm);
        This->pcm = NULL;
        err = snd_pcm_open(&pcm, WOutDev[This->drv->wDevID].pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
        if (err < 0)
        {
            WARN("Cannot open sound device: %s\n", snd_strerror(err));
            return DSERR_BUFFERLOST;
        }
    }

    /* Set some defaults */
    snd_pcm_hw_params_any(pcm, hw_params);
    err = snd_pcm_hw_params_set_channels(pcm, hw_params, pwfx->nChannels);
    if (err < 0) { WARN("Could not set channels to %d\n", pwfx->nChannels); goto err; }

    err = snd_pcm_hw_params_set_format(pcm, hw_params, format);
    if (err < 0) { WARN("Could not set format to %d bpp\n", pwfx->wBitsPerSample); goto err; }

    /* Alsa's rate resampling is only used if the application specifically requests
     * a buffer at a certain frequency, else it is better to disable it due to unwanted
     * side effects, which may include: Less granular pointer, changing buffer sizes, etc
     */
#if SND_LIB_VERSION >= 0x010009
    snd_pcm_hw_params_set_rate_resample(pcm, hw_params, 0);
#endif

    err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, NULL);
    if (err < 0) { rate = pwfx->nSamplesPerSec; WARN("Could not set rate\n"); goto err; }

    if (!ALSA_NearMatch(rate, pwfx->nSamplesPerSec))
    {
        WARN("Could not set sound rate to %d, but instead to %d\n", pwfx->nSamplesPerSec, rate);
        pwfx->nSamplesPerSec = rate;
        pwfx->nAvgBytesPerSec = rate * pwfx->nBlockAlign;
        /* Let DirectSound detect this */
    }

    snd_pcm_hw_params_set_periods_integer(pcm, hw_params);
    snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, NULL);
    buffer_time = 10000;
    snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &buffer_time, NULL);

    err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);
    buffer_time = 16;
    snd_pcm_hw_params_set_periods_near(pcm, hw_params, &buffer_time, NULL);

    if (!This->mmap)
    {
        HeapFree(GetProcessHeap(), 0, This->mmap_buffer);
        This->mmap_buffer = NULL;
    }

    err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
    if (err >= 0)
        This->mmap = 1;
    else
    {
        This->mmap = 0;
        err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
    }

    err = snd_pcm_hw_params(pcm, hw_params);

    /* ALSA needs at least 3 buffers to work successfully */
    This->mmap_commitahead = 3 * psize;
    while (This->mmap_commitahead <= 512)
        This->mmap_commitahead += psize;

    if (This->pcm)
    {
        snd_pcm_drop(This->pcm);
        snd_pcm_close(This->pcm);
    }
    This->pcm = pcm;
    snd_pcm_prepare(This->pcm);
    DSDB_CreateMMAP(This);
    return S_OK;

    err:
    if (err < 0)
        WARN("Failed to apply changes: %s\n", snd_strerror(err));

    if (!This->pcm)
        This->pcm = pcm;
    else
        snd_pcm_close(pcm);

    if (This->pcm)
        snd_pcm_hw_params_current(This->pcm, This->hw_params);

    return DSERR_BADFORMAT;
}
Example #16
0
static size_t
alsa_configure (void)
{
  //<init:
  size_t chunk_bytes, bits_per_sample, bits_per_frame = 0;
  snd_pcm_uframes_t chunk_size, buffer_size = 0;
  snd_pcm_hw_params_t *params;
  unsigned int rate = DEFAULT_SPEED;
  int err;
  snd_pcm_hw_params_alloca (&params);
  //>
  //<defaults:

  err = snd_pcm_hw_params_any (AHandle, params);
  if (err < 0)
    {
      fprintf (stderr,
               "Broken configuration for this PCM: no configurations available");
      exit (EXIT_FAILURE);
    }

  //>
  //<Format:

  err = snd_pcm_hw_params_set_format (AHandle, params, DEFAULT_FORMAT);
  if (err < 0)
    {
      fprintf (stderr, "Sample format non available");
      exit (EXIT_FAILURE);
    }

  //>
  //<Channels:

  err = snd_pcm_hw_params_set_channels (AHandle, params, 1);
  if (err < 0)
    {
      fprintf (stderr, "Channels count non available");
      exit (EXIT_FAILURE);
    }

  //>
  //<Rate:

  err = snd_pcm_hw_params_set_rate_near (AHandle, params, &rate, 0);
  assert (err >= 0);

  //>
  //<Access Mode:
  err = snd_pcm_hw_params_set_access (AHandle, params,
                                      SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err < 0)
    {
      fprintf (stderr, "Access type not available");
      exit (EXIT_FAILURE);
    }
  //>
  //< Set things explicitly if DEBUG
#ifdef DEBUG

  //<Compute buffer_time:
  unsigned int period_time = 0;
  unsigned int buffer_time = 0;
  snd_pcm_uframes_t period_frames = 0;
  snd_pcm_uframes_t buffer_frames = 0;
  // affected by defined buffer_size  (e.g. via asoundrc)
  if (buffer_time == 0 && buffer_frames == 0)
    {
      err = snd_pcm_hw_params_get_buffer_time (params, &buffer_time, 0);
      assert (err >= 0);
      if (buffer_time > 500000) //usecs
        buffer_time = 500000;
    }
  //>
  //<Compute period_time:

  if (period_time == 0 && period_frames == 0)
    {
      if (buffer_time > 0)
        period_time = buffer_time / 4;
      else
        period_frames = buffer_frames / 4;
    }
  if (period_time > 0)
    err = snd_pcm_hw_params_set_period_time_near (AHandle, params,
                                                  &period_time, 0);
  else
    err = snd_pcm_hw_params_set_period_size_near (AHandle, params,
                                                  &period_frames, 0);
  assert (err >= 0);
  if (buffer_time > 0)
    {
      err = snd_pcm_hw_params_set_buffer_time_near (AHandle, params,
                                                    &buffer_time, 0);
    }
  else
    {
      err = snd_pcm_hw_params_set_buffer_size_near (AHandle, params,
                                                    &buffer_frames);
    }
  assert (err >= 0);

  //>
#endif

  //>
  //<Commit hw params:
  err = snd_pcm_hw_params (AHandle, params);
  if (err < 0)
    {
      fprintf (stderr, "Unable to install hw params:");
      exit (EXIT_FAILURE);
    }
  //>
  //<finalize chunk_size and buffer_size:

  snd_pcm_hw_params_get_period_size (params, &chunk_size, 0);
  snd_pcm_hw_params_get_buffer_size (params, &buffer_size);
  if (chunk_size == buffer_size)
    {
      fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)",
               chunk_size, buffer_size);
      exit (EXIT_FAILURE);
    }

  //>
  //< If DEBUG: SW Params Configure transfer:

#ifdef DEBUG
  size_t n;
  snd_pcm_uframes_t xfer_align;
  snd_pcm_uframes_t start_threshold, stop_threshold;
  int start_delay = 5;
  int stop_delay = 0;
  snd_pcm_sw_params_t *swParams;
  snd_pcm_sw_params_alloca (&swParams);
  snd_pcm_sw_params_current (AHandle, swParams);
  err = snd_pcm_sw_params_get_xfer_align (swParams, &xfer_align);
  if (err < 0)
    {
      fprintf (stderr, "Unable to obtain xfer align\n");
      exit (EXIT_FAILURE);
    }
  // round up to closest transfer boundary
  n = (buffer_size / xfer_align) * xfer_align;
  if (start_delay <= 0)
    {
      start_threshold =
        (snd_pcm_uframes_t) (n + (double) rate * start_delay / 1000000);
    }
  else
    start_threshold =
      (snd_pcm_uframes_t) ((double) rate * start_delay / 1000000);
  if (start_threshold < 1)
    start_threshold = 1;
  if (start_threshold > n)
    start_threshold = n;
  err =
    snd_pcm_sw_params_set_start_threshold (AHandle, swParams,
                                           start_threshold);
  assert (err >= 0);
  if (stop_delay <= 0)
    stop_threshold =
      (snd_pcm_uframes_t) (buffer_size +
                           (double) rate * stop_delay / 1000000);
  else
    stop_threshold =
      (snd_pcm_uframes_t) ((double) rate * stop_delay / 1000000);
  err =
    snd_pcm_sw_params_set_stop_threshold (AHandle, swParams, stop_threshold);
  assert (err >= 0);

  err = snd_pcm_sw_params_set_xfer_align (AHandle, swParams, xfer_align);
  assert (err >= 0);

  if (snd_pcm_sw_params (AHandle, swParams) < 0)
    {
      fprintf (stderr, "unable to install sw params:");
      exit (EXIT_FAILURE);
    }
#endif

  //>
  bits_per_sample = snd_pcm_format_physical_width (DEFAULT_FORMAT);
  bits_per_frame = bits_per_sample * 1; //mono
  chunk_bytes = chunk_size * bits_per_frame / 8;
  return chunk_bytes;
}
Example #17
0
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods ) {
	int err, dir=0;
	unsigned int buffer_time;
	unsigned int period_time;
	unsigned int rrate;
	unsigned int rchannels;

	/* choose all parameters */
	err = snd_pcm_hw_params_any(handle, params);
	if (err < 0) {
		printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
		return err;
	}
	/* set the interleaved read/write format */
	err = snd_pcm_hw_params_set_access(handle, params, access);
	if (err < 0) {
		printf("Access type not available for playback: %s\n", snd_strerror(err));
		return err;
	}

	/* set the sample format */
	err = set_hwformat(handle, params);
	if (err < 0) {
		printf("Sample format not available for playback: %s\n", snd_strerror(err));
		return err;
	}
	/* set the count of channels */
	rchannels = channels;
	err = snd_pcm_hw_params_set_channels_near(handle, params, &rchannels);
	if (err < 0) {
		printf("Channels count (%i) not available for record: %s\n", channels, snd_strerror(err));
		return err;
	}
	if (rchannels != channels) {
		printf("WARNING: chennel count does not match (requested %d got %d)\n", channels, rchannels);
		num_channels = rchannels;
	}
	/* set the stream rate */
	rrate = rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
	if (err < 0) {
		printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
		return err;
	}
	if (rrate != rate) {
		printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, rrate);
		return -EINVAL;
	}
	/* set the buffer time */

	buffer_time = 1000000*(uint64_t)period*nperiods/rate;
	err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
	if (err < 0) {
		printf("Unable to set buffer time %i for playback: %s\n",  1000000*period*nperiods/rate, snd_strerror(err));
		return err;
	}
	err = snd_pcm_hw_params_get_buffer_size( params, &real_buffer_size );
	if (err < 0) {
		printf("Unable to get buffer size back: %s\n", snd_strerror(err));
		return err;
	}
	if( real_buffer_size != nperiods * period ) {
	    printf( "WARNING: buffer size does not match: (requested %d, got %d)\n", nperiods * period, (int) real_buffer_size );
	}
	/* set the period time */
	period_time = 1000000*(uint64_t)period/rate;
	err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
	if (err < 0) {
		printf("Unable to set period time %i for playback: %s\n", 1000000*period/rate, snd_strerror(err));
		return err;
	}
	err = snd_pcm_hw_params_get_period_size(params, &real_period_size, NULL );
	if (err < 0) {
		printf("Unable to get period size back: %s\n", snd_strerror(err));
		return err;
	}
	if( real_period_size != period ) {
	    printf( "WARNING: period size does not match: (requested %i, got %i)\n", period, (int)real_period_size );
	}
	/* write the parameters to device */
	err = snd_pcm_hw_params(handle, params);
	if (err < 0) {
		printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
		return err;
	}
	return 0;
}
Example #18
0
bool OutputALSA::initialize(quint32 freq, ChannelMap map, Qmmp::AudioFormat format)
{
    m_inited = false;

    if (pcm_handle)
        return false;

    if (snd_pcm_open(&pcm_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0)
    {
        qWarning ("OutputALSA: Error opening PCM device %s", pcm_name);
        return false;
    }

    // we need to configure

    uint rate = freq; /* Sample rate */
    uint exact_rate = freq;   /* Sample rate returned by */

    /* load settings from config */
    QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
    settings.beginGroup("ALSA");
    uint buffer_time = settings.value("buffer_time",500).toUInt()*1000;
    uint period_time = settings.value("period_time",100).toUInt()*1000;
    bool use_pause =  settings.value("use_snd_pcm_pause", false).toBool();
    settings.endGroup();

    snd_pcm_hw_params_t *hwparams = 0;
    snd_pcm_sw_params_t *swparams = 0;
    int err; //alsa error code

    //hw params
    snd_pcm_hw_params_alloca(&hwparams);
    if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
    {
        qWarning("OutputALSA: Can not read configuration for PCM device: %s", snd_strerror(err));
        return false;
    }
    if (m_use_mmap)
    {
        if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)
        {
            qWarning("OutputALSA: Error setting mmap access: %s", snd_strerror(err));
            m_use_mmap = false;
        }
    }
    if (!m_use_mmap)
    {
        if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
        {
            qWarning("OutputALSA: Error setting access: %s", snd_strerror(err));
            return false;
        }
    }
    snd_pcm_format_t alsa_format = SND_PCM_FORMAT_UNKNOWN;
    switch (format)
    {
    case Qmmp::PCM_S8:
        alsa_format = SND_PCM_FORMAT_S8;
        break;
    case Qmmp::PCM_S16LE:
        alsa_format = SND_PCM_FORMAT_S16_LE;
        break;
    case Qmmp::PCM_S24LE:
        alsa_format = SND_PCM_FORMAT_S24_LE;
        break;
    case Qmmp::PCM_S32LE:
        alsa_format = SND_PCM_FORMAT_S32_LE;
        break;
    default:
        qWarning("OutputALSA: unsupported format detected");
        return false;
    }
    if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, alsa_format)) < 0)
    {
        qDebug("OutputALSA: Error setting format: %s", snd_strerror(err));
        return false;
    }
    exact_rate = rate;

    if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0)) < 0)
    {
        qWarning("OutputALSA: Error setting rate: %s", snd_strerror(err));
        return false;
    }
    if (rate != exact_rate)
    {
        qWarning("OutputALSA: The rate %d Hz is not supported by your hardware.\n==> Using %d Hz instead.", rate, exact_rate);
        rate = exact_rate;
    }
    uint c = map.count();
    if ((err = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0)
    {
        qWarning("OutputALSA: Error setting channels: %s", snd_strerror(err));
        return false;
    }
    if (c != (uint)map.count())
    {
        qWarning("OutputALSA: The channel number %d is not supported by your hardware", map.count());
        qWarning("==> Using %d instead.", c);
    }
    if ((err = snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &period_time ,0)) < 0)
    {
        qWarning("OutputALSA: Error setting period time: %s", snd_strerror(err));
        return false;
    }
    if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffer_time ,0)) < 0)
    {
        qWarning("OutputALSA: Error setting buffer time: %s", snd_strerror(err));
        return false;
    }
    if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
    {
        qWarning("OutputALSA: Error setting HW params: %s", snd_strerror(err));
        return false;
    }
    //read some alsa parameters
    snd_pcm_uframes_t buffer_size = 0;
    snd_pcm_uframes_t period_size = 0;
    if ((err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size)) < 0)
    {
        qWarning("OutputALSA: Error reading buffer size: %s", snd_strerror(err));
        return false;
    }
    if ((err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0)) < 0)
    {
        qWarning("OutputALSA: Error reading period size: %s", snd_strerror(err));
        return false;
    }
    //swparams
    snd_pcm_sw_params_alloca(&swparams);
    snd_pcm_sw_params_current(pcm_handle, swparams);
    if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,
               buffer_size - period_size)) < 0)
        qWarning("OutputALSA: Error setting threshold: %s", snd_strerror(err));
    if ((err = snd_pcm_sw_params(pcm_handle, swparams)) < 0)
    {
        qWarning("OutputALSA: Error setting SW params: %s", snd_strerror(err));
        return false;
    }
    //setup needed values
    m_chunk_size = period_size;
    m_can_pause = snd_pcm_hw_params_can_pause(hwparams) && use_pause;
    qDebug("OutputALSA: can pause: %d", m_can_pause);

    ChannelMap out_map = map;
#if (SND_LIB_VERSION >= 0x01001B)
    //channel map configuration
    snd_pcm_chmap_t *chmap = snd_pcm_get_chmap(pcm_handle);
    if(chmap)
    {
        out_map.clear();
        char tmp[256];
        memset(tmp,0,256);
        snd_pcm_chmap_print(chmap, 256, tmp);
        qDebug("OutputALSA: received channel map: %s",tmp);

        for(uint i = 0; i < chmap->channels; ++i)
        {
            if(m_alsa_channels.keys().contains(chmap->pos[i]))
                out_map.append(m_alsa_channels.value(chmap->pos[i]));
            else
                out_map.append(Qmmp::CHAN_NULL);
        }
        free(chmap);
    }
    else
        qWarning("OutputALSA: Unable to receive current channel map");
#endif
    configure(exact_rate, out_map, format); //apply configuration
    //create alsa prebuffer;
    m_prebuf_size = 2 * snd_pcm_frames_to_bytes(pcm_handle, m_chunk_size); //buffer for two periods
    m_prebuf = (uchar *)malloc(m_prebuf_size);
    m_inited = true;
    return true;
}
Example #19
0
static void *_msynth_thread_main(void *arg)
{
    int i;
    int err;
    int sample;
    int processed;

    struct sampleclock sc = {0, 0, 0.0f, 0.0f};
    msynth_frame fb = NULL;

    puts("synthread: started");

    /* Begin initialization of ALSA */
    /* snd_pcm_open(pcm_handle, device_name, stream_type, open_mode) */
    err = snd_pcm_open(&pcm, config.device_name, SND_PCM_STREAM_PLAYBACK, 0);
    ALSERT("opening audio device");

    /* First ALSA hardware settings */

    /* Allocate HW params */
    err = snd_pcm_hw_params_malloc(&hw_p);
    ALSERT("allocating hw params");

    /* Get default HW parameters */
    err = snd_pcm_hw_params_any(pcm, hw_p);
    ALSERT("requesting hw default params");

    /* Disable software resampling */
    err = snd_pcm_hw_params_set_rate_resample(pcm, hw_p, config.resample);
    ALSERT("disabling software resampling");

    /* Configure sample rate */
    if (config.srate != -1)
        srate = config.srate;
    else {
        /* Get maximum hardware samplerate */
        err = snd_pcm_hw_params_get_rate_max(hw_p, &srate, &dir);
        ALSERT("requesting maximum hardware samplerate");
    }

    /* Set sample rate 
     * snd_pcm_hw_params_set_rate_near(pcn, hw_p, *rate,
     *      0 (== set exact rate))
     */
    err = snd_pcm_hw_params_set_rate_near(pcm, hw_p, &srate, 0);
    ALSERT("setting samplerate");
    printf("synthread: Detected samplerate of %u\n", srate);

    /* RW interleaved access (means we will use the snd_pcm_writei function) */
    err = snd_pcm_hw_params_set_access(pcm, hw_p,
        SND_PCM_ACCESS_RW_INTERLEAVED);
    ALSERT("setting access mode");

    /* native-endian 16-bit signed sample format */
    err = snd_pcm_hw_params_set_format(pcm, hw_p, SND_PCM_FORMAT_S16);
    ALSERT("setting sample format");

    /* Switch to 2.0ch audio */
    err = snd_pcm_hw_params_set_channels(pcm, hw_p, 2);
    ALSERT("switching to 2.0ch audio");

    if (config.buffer_time != -1) {
        /* Set configured buffer time */
        err = snd_pcm_hw_params_set_buffer_time_near(pcm, hw_p,
            &config.buffer_time, &dir);
        ALSERT("setting buffer time");

        /* Fetch resulting size */
        err = snd_pcm_hw_params_get_buffer_size(hw_p, &buffer_size);
        ALSERT("getting buffer size");
    } else {
        /* Since we want the interactive synthesizer to be very responsive
         * select a minimum buffer size.
         */
        err = snd_pcm_hw_params_set_buffer_size_first(pcm, hw_p, &buffer_size);
        ALSERT("setting buffer size");
    }

    printf("synthread: Selected buffersize of %lu\n", buffer_size);
    printf("synthread: Response delay is approximately %.2f ms\n",
        (double)buffer_size / (double)srate * 1000.0);

    if (config.period_time != -1) {
        err = snd_pcm_hw_params_set_period_time_near(pcm, hw_p,
            &config.period_time, &dir);
        ALSERT("setting period time");

        err = snd_pcm_hw_params_get_period_size(hw_p, &period_size, &dir);
        ALSERT("getting period size");
    } else {
        /* Select a period time of half the buffer time
         * since this improves processing performance
         */
        err = snd_pcm_hw_params_set_period_size_last(pcm, hw_p, &period_size, &dir);
        ALSERT("setting period size");
    }

    if (dir)
        printf("synthread: Selected period size near %lu\n", period_size);
    else
        printf("synthread: Selected period size of %lu\n", period_size);

    /* write hw parameters to device */
    err = snd_pcm_hw_params(pcm, hw_p);
    ALSERT("writing hw params");

    /* Begin ALSA software side setup */

    /* Allocate SW params */
    err = snd_pcm_sw_params_malloc(&sw_p);
    ALSERT("allocating sw params");

    /* Request software current settings */
    err = snd_pcm_sw_params_current(pcm, sw_p);
    ALSERT("requesting current sw params");

    /* Automatically start playing after the first period is written */
    err = snd_pcm_sw_params_set_start_threshold(pcm, sw_p, period_size);
    ALSERT("settings start threshold");

    /* XRUN when buffer is empty */
    err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_p, buffer_size * 2);
    ALSERT("setting stop threshold");

    /* Block synthesizer when there is not at least period frames available */
    err = snd_pcm_sw_params_set_avail_min(pcm, sw_p, period_size);
    ALSERT("setting minimum free frames");

    /* Write software parameters */
    err = snd_pcm_sw_params(pcm, sw_p);
    ALSERT("writing sw params");
    printf("synthread: Audio system configured.\n");

    /* Prepare device for playback */
    err = snd_pcm_prepare(pcm);
    ALSERT("preparing device");

    /* Allocate a period sized framebuffer
     * (yup an audio buffer is in ALSA speak indeed called a framebuffer)
     */
    fb = malloc(sizeof(struct _msynth_frame) * period_size);
    if (!fb) {
        perror("malloc framebuffer failed");
        exit(1);
    }

    /* Set sampleclock to 0 */
    sc.samples = 0;
    sc.samplerate = srate;
    sc.cycle = 0.0f;
    sc.seconds = 0.0f;

    /* Initially the <root> variable describing the flow of sound within
     * the synthesizer is configured to be a NULL signal. (silence)
     */

    /* Signal successful completion of initialization */
    pthread_mutex_lock(&mutex);
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);

    /* -------------- Main loop --------------- */
    while (!shutdown) {
        /* Only during generation we need the synth tree to be static */
        synth_lock_graphs();

        for (i = 0; i < period_size; i++) {
            /* Evaluate variables */
            ssv_eval(sc);

            sample = (int)(32767.5 * ssv_get_var_eval("left") * volume);

            /* Clip samples */
            if (sample > 32767) sample = 32767;
            if (sample < -32768) sample = -32768;

            fb[i].left = (short)sample;

            sample = (int)(32767.5 * ssv_get_var_eval("right") * volume);

            /* Clip samples */
            if (sample > 32767) sample = 32767;
            if (sample < -32768) sample = -32768;

            fb[i].right = (short)sample;

            sc = sc_from_samples(sc.samplerate, sc.samples + 1);
        }

        synth_unlock_graphs();

        /* Send audio to sound card */
        processed = 0;
        while (processed != period_size) {
            err = snd_pcm_writei(pcm, fb + processed, period_size - processed);

            /* Retry on interruption by signal */
            if (err == -EAGAIN)
                continue;

            /* Recover from XRUN/suspend */
            if (err < 0) {
                err = synth_recover(err);
                ALSERT("sending audio");
                continue;
            }

            /* Update processed samples */
            processed += err;
        }
    }

    puts("synthread: shutting down");

    /* Dump any statistics recorded */
    if (recover_resumes)
        printf("synthread: Device was resumed %i times\n", recover_resumes);
    if (recover_xruns)
        printf("synthread: %i xrun recoveries were needed\n", recover_xruns);
    printf("synthread: processed %i samples\n", sc.samples);

    /* Wait for playback to complete */
    err = snd_pcm_drain(pcm);
    ALSERT("draining device");

    /* Shutdown PCM device */
    err = snd_pcm_close(pcm);
    ALSERT("closing audio device");

    /* Clean up parameters */
    snd_pcm_hw_params_free(hw_p);
    snd_pcm_sw_params_free(sw_p);

    return NULL;
}
int 
set_hwparams(snd_pcm_t *handle, int sampleRate, int channels, int bufferSize)
{
    snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;

    int ret, dir;

    snd_pcm_hw_params_t *hwparams;

    snd_pcm_hw_params_alloca(&hwparams);

    /* choose all parameters */
    ret = snd_pcm_hw_params_any(handle, hwparams);
    if (ret < 0) {
        fprintf(stderr, "Broken configuration for playback: "
	    "no configurations available: %s\n", snd_strerror(ret));
        return ret;
    }
    /* set hardware resampling */
    ret = snd_pcm_hw_params_set_rate_resample(handle, hwparams, resample);
    if (ret < 0) {
	fprintf(stderr, "Resampling setup failed for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* set the interleaved read/write format */
    ret = snd_pcm_hw_params_set_access(handle, hwparams, access);
    if (ret < 0) {
        fprintf(stderr, "Access type not available for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* set the sample format */
    ret = snd_pcm_hw_params_set_format(handle, hwparams, format);
    if (ret < 0) {
        fprintf(stderr, "Sample format not available for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* set the count of channels */
    ret = snd_pcm_hw_params_set_channels(handle, hwparams, channels);
    if (ret < 0) {
        fprintf(stderr, 
	    "Channels count (%d) not available for playbacks: %s\n", 
	    channels, snd_strerror(ret));
        return ret;
    } 

    /* set the stream rate */
    int rate = sampleRate;

    ret = snd_pcm_hw_params_set_rate(handle, hwparams, rate, 0);
    if (ret < 0) {
        fprintf(stderr, "Rate %dHz not available for playback: %s\n", 
	    sampleRate, snd_strerror(ret));
        return ret;
    }

    if (rate != sampleRate) {
        fprintf(stderr, "Rate doesn't match (requested %dHz, get %dHz)\n", 
	    rate, ret);
        return -EINVAL;
    } 

    /* set the buffer frames */
    unsigned int buffer_frames = bufferSize / 2 / channels;  // bytes to frames

    ret = snd_pcm_hw_params_set_buffer_size(handle, hwparams, buffer_frames);
    if (ret < 0) {
        fprintf(stderr, "Unable to set buffer size %d for playback: %s\n", 
	    buffer_frames, snd_strerror(ret));
        return ret;
    }

    /* set the period time */
    dir = 0;
    ret = snd_pcm_hw_params_set_period_time_near(handle, hwparams, 
	&period_time, &dir);
    if (ret < 0) {
        fprintf(stderr, "Unable to set period time %d for playback: %s\n", 
	    period_time, snd_strerror(ret));
        return ret;
    }

    /* write the parameters to device */
    ret = snd_pcm_hw_params(handle, hwparams);
    if (ret < 0) {
        fprintf(stderr, "Unable to set hw params for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    dump_hwparams(handle);
}
Example #21
0
static int set_snd_pcm_params(struct bat *bat, struct snd_pcm_container *sndpcm)
{
    snd_pcm_format_t format;
    snd_pcm_hw_params_t *params;
    unsigned int buffer_time = 0;
    unsigned int period_time = 0;
    unsigned int rate;
    int err;
    const char *device_name = snd_pcm_name(sndpcm->handle);

    /* Allocate a hardware parameters object. */
    snd_pcm_hw_params_alloca(&params);

    /* Fill it in with default values. */
    err = snd_pcm_hw_params_any(sndpcm->handle, params);
    if (err < 0) {
        loge(E_SETDEV S_DEFAULT, "%s: %s(%d)",
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    /* Set access mode */
    err = snd_pcm_hw_params_set_access(sndpcm->handle, params,
                                       SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
        loge(E_SETDEV S_ACCESS, "%s: %s(%d)",
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    /* Set format */
    switch (bat->sample_size) {
    case 1:
        format = SND_PCM_FORMAT_S8;
        break;
    case 2:
        format = SND_PCM_FORMAT_S16_LE;
        break;
    case 3:
        format = SND_PCM_FORMAT_S24_3LE;
        break;
    case 4:
        format = SND_PCM_FORMAT_S32_LE;
        break;
    default:
        loge(E_PARAMS S_PCMFORMAT, "size=%d", bat->sample_size);
        goto fail_exit;
    }
    err = snd_pcm_hw_params_set_format(sndpcm->handle, params, format);
    if (err < 0) {
        loge(E_SETDEV S_PCMFORMAT, "%d %s: %s(%d)",
             format,
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    /* Set channels */
    err = snd_pcm_hw_params_set_channels(sndpcm->handle,
                                         params, bat->channels);
    if (err < 0) {
        loge(E_SETDEV S_CHANNELS, "%d %s: %s(%d)",
             bat->channels,
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    /* Set sampling rate */
    rate = bat->rate;
    err = snd_pcm_hw_params_set_rate_near(sndpcm->handle,
                                          params, &bat->rate,
                                          0);
    if (err < 0) {
        loge(E_SETDEV S_SAMPLERATE, "%d %s: %s(%d)",
             bat->rate,
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }
    if ((float) rate * 1.05 < bat->rate
            || (float) rate * 0.95 > bat->rate) {
        loge(E_PARAMS S_SAMPLERATE, "requested %dHz, got %dHz",
             rate, bat->rate);
        goto fail_exit;
    }

    if (snd_pcm_hw_params_get_buffer_time_max(params,
            &buffer_time, 0) < 0) {
        loge(E_GETDEV S_BUFFERTIME, "%d %s: %s(%d)",
             buffer_time,
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    if (buffer_time > 500000)
        buffer_time = 500000;
    /* Was 4, changed to 8 to remove reduce capture overrun */
    period_time = buffer_time / 8;

    /* Set buffer time and period time */
    err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, params,
            &buffer_time, 0);
    if (err < 0) {
        loge(E_SETDEV S_BUFFERTIME, "%d %s: %s(%d)",
             buffer_time,
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle, params,
            &period_time, 0);
    if (err < 0) {
        loge(E_SETDEV S_PERIODTIME, "%d %s: %s(%d)",
             period_time,
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    /* Write the parameters to the driver */
    if (snd_pcm_hw_params(sndpcm->handle, params) < 0) {
        loge(E_SETDEV S_HWPARAMS, "%s: %s(%d)",
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    err = snd_pcm_hw_params_get_period_size(params,
                                            &sndpcm->period_size, 0);
    if (err < 0) {
        loge(E_GETDEV S_PERIODSIZE, "%zd %s: %s(%d)",
             sndpcm->period_size,
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    err = snd_pcm_hw_params_get_buffer_size(params, &sndpcm->buffer_size);
    if (err < 0) {
        loge(E_GETDEV S_BUFFERSIZE, "%zd %s: %s(%d)",
             sndpcm->buffer_size,
             device_name, snd_strerror(err), err);
        goto fail_exit;
    }

    if (sndpcm->period_size == sndpcm->buffer_size) {
        loge(E_PARAMS, "can't use period equal to buffer size (%zd)",
             sndpcm->period_size);
        goto fail_exit;
    }

    err = snd_pcm_format_physical_width(format);
    if (err < 0) {
        loge(E_PARAMS, "snd_pcm_format_physical_width: %d", err);
        goto fail_exit;
    }
    sndpcm->sample_bits = err;

    sndpcm->frame_bits = sndpcm->sample_bits * bat->channels;

    /* Calculate the period bytes */
    sndpcm->period_bytes = sndpcm->period_size * sndpcm->frame_bits / 8;
    sndpcm->buffer = (char *) malloc(sndpcm->period_bytes);
    if (sndpcm->buffer == NULL) {
        loge(E_MALLOC, "size=%zd", sndpcm->period_bytes);
        goto fail_exit;
    }

    return 0;

fail_exit:
    return -1;
}
Example #22
0
static void
init_audio(const char* devname)
{
  snd_pcm_hw_params_t* hwparams = 0;
  snd_pcm_sw_params_t* swparams = 0;
  snd_pcm_uframes_t    bufsize  = 0;
  unsigned int         buftime  = 1000000;
  unsigned int         pertime  = 50000;
  int                  dir      = 0;
  int                  rc;

  if ((rc = snd_output_stdio_attach(&output, stderr, 0)) < 0)
    exit_snd_error(rc, "log output");

  if ((rc = snd_pcm_open(&audio, devname, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
    exit_snd_error(rc, "opening device");

  if ((rc = snd_pcm_hw_params_malloc(&hwparams)) < 0)
    exit_snd_error(rc, "hardware parameters");

  if ((rc = snd_pcm_hw_params_any(audio, hwparams)) < 0)
    exit_snd_error(rc, "hardware parameters");

  if ((rc = snd_pcm_hw_params_set_rate_resample(audio, hwparams, 0)) < 0)
    exit_snd_error(rc, "hardware parameters");

  if ((rc = snd_pcm_hw_params_set_access(audio, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
    exit_snd_error(rc, "access type");

  if ((rc = snd_pcm_hw_params_set_format(audio, hwparams, SND_PCM_FORMAT_S16)) < 0)
    exit_snd_error(rc, "sample format");

  if ((rc = snd_pcm_hw_params_set_channels_near(audio, hwparams, &n_channels)) < 0)
    exit_snd_error(rc, "number of channels");

  if ((rc = snd_pcm_hw_params_set_rate_near(audio, hwparams, &samplerate, &dir)) < 0)
    exit_snd_error(rc, "sample rate");

  if ((rc = snd_pcm_hw_params_set_buffer_time_near(audio, hwparams, &buftime, &dir)) < 0)
    exit_snd_error(rc, "buffer time");

  if ((rc = snd_pcm_hw_params_set_period_time_near(audio, hwparams, &pertime, &dir)) < 0)
    exit_snd_error(rc, "period time");

  if ((rc = snd_pcm_hw_params(audio, hwparams)) < 0)
    exit_snd_error(rc, "applying hardware parameters");

  if ((rc = snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize)) < 0)
    exit_snd_error(rc, "buffer size");

  if ((rc = snd_pcm_hw_params_get_period_size(hwparams, &periodsize, &dir)) < 0)
    exit_snd_error(rc, "period size");

  snd_pcm_hw_params_free(hwparams);

  if ((rc = snd_pcm_sw_params_malloc(&swparams)) < 0)
    exit_snd_error(rc, "software parameters");

  if ((rc = snd_pcm_sw_params_current(audio, swparams)) < 0)
    exit_snd_error(rc, "software parameters");

  if ((rc = snd_pcm_sw_params_set_start_threshold(audio, swparams,
                                                  bufsize / periodsize * periodsize)) < 0)
    exit_snd_error(rc, "start threshold");

  if ((rc = snd_pcm_sw_params(audio, swparams)) < 0)
    exit_snd_error(rc, "applying software parameters");

  snd_pcm_sw_params_free(swparams);

  if ((rc = snd_pcm_prepare(audio)) < 0)
    exit_snd_error(rc, "preparing device");
}
Example #23
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 #24
0
/*hard ware parameter set*/
static int set_hwparams(snd_pcm_t *handle,snd_pcm_hw_params_t *params,snd_pcm_access_t access)
{
	unsigned int rrate;
	snd_pcm_uframes_t size;
	int err, dir;
	/* choose all parameters */
	err = snd_pcm_hw_params_any(handle, params);
	if (err < 0) 
	{
		printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
		return err;
	}
	/* set hardware resampling */
	err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
	if (err < 0) 
	{
		printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
		return err;
	}
	/* set the interleaved read/write format */
	err = snd_pcm_hw_params_set_access(handle, params, access);
	if (err < 0)
	{
		printf("Access type not available for playback: %s\n", snd_strerror(err));
		return err;
	}
	/* set the sample format */
	err = snd_pcm_hw_params_set_format(handle, params, format);
	if (err < 0) 
	{
		printf("Sample format not available for playback: %s\n", snd_strerror(err));
		return err;
	}
	/* set the count of channels */
	err = snd_pcm_hw_params_set_channels(handle, params, channels);
	if (err < 0)
	{
		printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
		return err;
	}
	/* set the stream rate */
	rrate = rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
	if (err < 0) 
	{
		printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
		return err;
	}
	if (rrate != rate) 
	{
		printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
		return -EINVAL;
	}
	/* set the buffer time */
	err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
	if (err < 0)
	 {
		printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
		return err;
	}
	err = snd_pcm_hw_params_get_buffer_size(params, &size);
	if (err < 0)
	 {
		printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
		return err;
	}
	buffer_size = size;

	/* set the period time */
	err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
	if (err < 0)
	 {
		printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
		return err;
	}
/*
	snd_pcm_uframes_t periodsize=800;
	 err = snd_pcm_hw_params_set_period_size(handle, params,910,0);
	printf("period near %d   %d\r\n",dir,periodsize);

	if (err < 0) {
	printf("Unable to set period size   %s\n ", snd_strerror(err));
	return err;
	}*/
	err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
	printf("size or the period_size: %ld\r\n",size);
	if (err < 0) 
	{
		printf("Unable to get period size for playback: %s\n", snd_strerror(err));
		return err;
	}
	period_size = size;
	/* write the parameters to device */
	err = snd_pcm_hw_params(handle, params);
	if (err < 0) 
	{
		printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
		return err;
	}
	return 0;
}
Example #25
0
static void set_params(void)
{
	snd_pcm_hw_params_t *params;
	snd_pcm_sw_params_t *swparams;
	snd_pcm_uframes_t buffer_size;
	int err;
	size_t n;
	snd_pcm_uframes_t xfer_align;
	unsigned int rate;
	snd_pcm_uframes_t start_threshold, stop_threshold;
	snd_pcm_hw_params_alloca(&params);
	snd_pcm_sw_params_alloca(&swparams);
	err = snd_pcm_hw_params_any(handle, params);
	if (err < 0) {
		error(_("Broken configuration for this PCM: no configurations available"));
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
	if (err < 0) {
		error(_("Access type not available"));
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_format(handle, params, hwparams.format);
	if (err < 0) {
		error(_("Sample format non available"));
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels);
	if (err < 0) {
		error(_("Channels count non available"));
		exit(EXIT_FAILURE);
	}

#if 0
	err = snd_pcm_hw_params_set_periods_min(handle, params, 2);
	assert(err >= 0);
#endif
	rate = hwparams.rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0);
	assert(err >= 0);
	if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) {
		if (!quiet_mode) {
			char plugex[64];
			const char *pcmname = snd_pcm_name(handle);
			fprintf(stderr, _("Warning: rate is not accurate (requested = %iHz, got = %iHz)\n"), rate, hwparams.rate);
			if (! pcmname || strchr(snd_pcm_name(handle), ':'))
				*plugex = 0;
			else
				snprintf(plugex, sizeof(plugex), "(-Dplug:%s)",
					 snd_pcm_name(handle));
			fprintf(stderr, _("         please, try the plug plugin %s\n"),
				plugex);
		}
	}
	rate = hwparams.rate;
	if (buffer_time == 0 && buffer_frames == 0) {
		err = snd_pcm_hw_params_get_buffer_time_max(params,
							    &buffer_time, 0);
		assert(err >= 0);
		if (buffer_time > 500000)
			buffer_time = 500000;
	}
	if (period_time == 0 && period_frames == 0) {
		if (buffer_time > 0)
			period_time = buffer_time / 4;
		else
			period_frames = buffer_frames / 4;
	}
	if (period_time > 0)
		err = snd_pcm_hw_params_set_period_time_near(handle, params,
							     &period_time, 0);
	else
		err = snd_pcm_hw_params_set_period_size_near(handle, params,
							     &period_frames, 0);
	assert(err >= 0);
	if (buffer_time > 0) {
		err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
							     &buffer_time, 0);
	} else {
		err = snd_pcm_hw_params_set_buffer_size_near(handle, params,
							     &buffer_frames);
	}
	assert(err >= 0);
	err = snd_pcm_hw_params(handle, params);
	if (err < 0) {
		error(_("Unable to install hw params:"));
		snd_pcm_hw_params_dump(params, log);
		exit(EXIT_FAILURE);
	}
	snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
	snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
	if (chunk_size == buffer_size) {
		error(_("Can't use period equal to buffer size (%lu == %lu)"),
		      chunk_size, buffer_size);
		exit(EXIT_FAILURE);
	}
	snd_pcm_sw_params_current(handle, swparams);
	err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
	if (err < 0) {
		error(_("Unable to obtain xfer align\n"));
		exit(EXIT_FAILURE);
	}
	if (sleep_min)
		xfer_align = 1;
	err = snd_pcm_sw_params_set_sleep_min(handle, swparams,
					      sleep_min);
	assert(err >= 0);
	if (avail_min < 0)
		n = chunk_size;
	else
		n = (double) rate * avail_min / 1000000;
	err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);

	// round up to closest transfer boundary
	n = (buffer_size / xfer_align) * xfer_align;
	start_threshold = n;
	if (start_threshold < 1)
		start_threshold = 1;
	if (start_threshold > n)
		start_threshold = n;
	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
	assert(err >= 0);
	stop_threshold = buffer_size;
	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
	assert(err >= 0);

	err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
	assert(err >= 0);

	if (snd_pcm_sw_params(handle, swparams) < 0) {
		error(_("unable to install sw params:"));
		snd_pcm_sw_params_dump(swparams, log);
		exit(EXIT_FAILURE);
	}

	bits_per_sample = snd_pcm_format_physical_width(hwparams.format);
	bits_per_frame = bits_per_sample * hwparams.channels;
	chunk_bytes = chunk_size * bits_per_frame / 8;
	audiobuf = realloc(audiobuf, chunk_bytes);
	if (audiobuf == NULL) {
		error(_("not enough memory"));
		exit(EXIT_FAILURE);
	}
	// fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size);
}
Example #26
0
bool QAlsaAudioInput::open()
{
#ifdef DEBUG_AUDIO
    QTime now(QTime::currentTime());
    qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
#endif
    clockStamp.restart();
    timeStamp.restart();
    elapsedTimeOffset = 0;

    int dir;
    int err = 0;
    int count=0;
    unsigned int sampleRate=settings.sampleRate();

    if (!settings.isValid()) {
        qWarning("QAudioInput: open error, invalid format.");
    } else if (settings.sampleRate() <= 0) {
        qWarning("QAudioInput: open error, invalid sample rate (%d).",
                 settings.sampleRate());
    } else {
        err = -1;
    }

    if (err == 0) {
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        emit errorChanged(errorState);
        return false;
    }


    QString dev = QString(QLatin1String(m_device.constData()));
    QList<QByteArray> devices = QAlsaAudioDeviceInfo::availableDevices(QAudio::AudioInput);
    if(dev.compare(QLatin1String("default")) == 0) {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        if (devices.size() > 0)
            dev = QLatin1String(devices.first());
        else
            return false;
#else
        dev = QLatin1String("hw:0,0");
#endif
    } else {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = QLatin1String(m_device);
#else
        int idx = 0;
        char *name;

        QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData());

        while(snd_card_get_name(idx,&name) == 0) {
            if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0)
                break;
            idx++;
        }
        dev = QString(QLatin1String("hw:%1,0")).arg(idx);
#endif
    }

    // Step 1: try and open the device
    while((count < 5) && (err < 0)) {
        err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
        if(err < 0)
            count++;
    }
    if (( err < 0)||(handle == 0)) {
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        emit stateChanged(deviceState);
        return false;
    }
    snd_pcm_nonblock( handle, 0 );

    // Step 2: Set the desired HW parameters.
    snd_pcm_hw_params_alloca( &hwparams );

    bool fatal = false;
    QString errMessage;
    unsigned int chunks = 8;

    err = snd_pcm_hw_params_any( handle, hwparams );
    if ( err < 0 ) {
        fatal = true;
        errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_any: err = %1").arg(err);
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_access( handle, hwparams, access );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_access: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = setFormat();
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_format: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channelCount() );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_channels: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &sampleRate, 0 );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params(handle, hwparams);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params: err = %1").arg(err);
        }
    }
    if( err < 0) {
        qWarning()<<errMessage;
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        emit stateChanged(deviceState);
        return false;
    }
    snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
    buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
    snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
    period_size = snd_pcm_frames_to_bytes(handle,period_frames);
    snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
    snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);

    // Step 3: Set the desired SW parameters.
    snd_pcm_sw_params_t *swparams;
    snd_pcm_sw_params_alloca(&swparams);
    snd_pcm_sw_params_current(handle, swparams);
    snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
    snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
    snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
    snd_pcm_sw_params(handle, swparams);

    // Step 4: Prepare audio
    ringBuffer.resize(buffer_size);
    snd_pcm_prepare( handle );
    snd_pcm_start(handle);

    // Step 5: Setup timer
    bytesAvailable = checkBytesReady();

    if(pullMode)
        connect(audioSource,SIGNAL(readyRead()),this,SLOT(userFeed()));

    // Step 6: Start audio processing
    chunks = buffer_size/period_size;
    timer->start(period_time*chunks/2000);

    errorState  = QAudio::NoError;

    totalTimeValue = 0;

    return true;
}
bool QAudioOutputPrivate::open()
{
    if(opened)
        return true;

#ifdef DEBUG_AUDIO
    QTime now(QTime::currentTime());
    qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
#endif
    timeStamp.restart();
    elapsedTimeOffset = 0;

    int dir;
    int err=-1;
    int count=0;
    unsigned int freakuency=settings.frequency();

    QString dev = QLatin1String(m_device.constData());
    QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput);
    if(dev.compare(QLatin1String("default")) == 0) {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = QLatin1String(devices.first().constData());
#else
        dev = QLatin1String("hw:0,0");
#endif
    } else {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = QLatin1String(m_device);
#else
        int idx = 0;
        char *name;

        QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData());

	while(snd_card_get_name(idx,&name) == 0) {
            if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0)
                break;
            idx++;
	}
        dev = QString(QLatin1String("hw:%1,0")).arg(idx);
#endif
    }

    // Step 1: try and open the device
    while((count < 5) && (err < 0)) {
        err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
        if(err < 0)
            count++;
    }
    if (( err < 0)||(handle == 0)) {
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        return false;
    }
    snd_pcm_nonblock( handle, 0 );

    // Step 2: Set the desired HW parameters.
    snd_pcm_hw_params_alloca( &hwparams );

    bool fatal = false;
    QString errMessage;
    unsigned int chunks = 8;

    err = snd_pcm_hw_params_any( handle, hwparams );
    if ( err < 0 ) {
        fatal = true;
        errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_any: err = %1").arg(err);
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_access( handle, hwparams, access );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_access: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = setFormat();
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_format: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
        if ( err < 0 ) {
            fatal = true;
                errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params(handle, hwparams);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params: err = %1").arg(err);
        }
    }
    if( err < 0) {
        qWarning()<<errMessage;
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        return false;
    }
    snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
    buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
    snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
    period_size = snd_pcm_frames_to_bytes(handle,period_frames);
    snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
    snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);

    // Step 3: Set the desired SW parameters.
    snd_pcm_sw_params_t *swparams;
    snd_pcm_sw_params_alloca(&swparams);
    snd_pcm_sw_params_current(handle, swparams);
    snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
    snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
    snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
    snd_pcm_sw_params(handle, swparams);

    // Step 4: Prepare audio
    if(audioBuffer == 0)
        audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)];
    snd_pcm_prepare( handle );
    snd_pcm_start(handle);

    // Step 5: Setup callback and timer fallback
    snd_async_add_pcm_handler(&ahandler, handle, async_callback, this);
    bytesAvailable = bytesFree();

    // Step 6: Start audio processing
    timer->start(period_time/1000);

    clockStamp.restart();
    timeStamp.restart();
    elapsedTimeOffset = 0;
    errorState  = QAudio::NoError;
    totalTimeValue = 0;
    opened = true;

    return true;
}
Example #28
0
static void set_params(void)
{
	snd_pcm_hw_params_t *params;
	snd_pcm_sw_params_t *swparams;
	snd_pcm_uframes_t buffer_size;
	int err;
	size_t n;
	unsigned int rate;
	snd_pcm_uframes_t start_threshold, stop_threshold;
	snd_pcm_hw_params_alloca(&params);
	snd_pcm_sw_params_alloca(&swparams);
	err = snd_pcm_hw_params_any(handle, params);
	if (err < 0) {
		error("Broken configuration for this PCM: no configurations available");
		exit(EXIT_FAILURE);
	}
	if (mmap_flag) {
		snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
		snd_pcm_access_mask_none(mask);
		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
		err = snd_pcm_hw_params_set_access_mask(handle, params, mask);
	} else if (interleaved)
		err = snd_pcm_hw_params_set_access(handle, params,
						   SND_PCM_ACCESS_RW_INTERLEAVED);
	else
		err = snd_pcm_hw_params_set_access(handle, params,
						   SND_PCM_ACCESS_RW_NONINTERLEAVED);
	if (err < 0) {
		error("Access type not available");
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_format(handle, params, hwparams.format);
	if (err < 0) {
		error("Sample format non available");
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels);
	if (err < 0) {
		error("Channels count non available");
		exit(EXIT_FAILURE);
	}

#if 0
	err = snd_pcm_hw_params_set_periods_min(handle, params, 2);
	assert(err >= 0);
#endif
	rate = hwparams.rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0);
	assert(err >= 0);
	if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) {
		if (!quiet_mode) {
			char plugex[64];
			const char *pcmname = snd_pcm_name(handle);
			fprintf(stderr, "Warning: rate is not accurate (requested = %iHz, got = %iHz)\n", rate, hwparams.rate);
			if (! pcmname || strchr(snd_pcm_name(handle), ':'))
				*plugex = 0;
			else
				snprintf(plugex, sizeof(plugex), "(-Dplug:%s)",
					 snd_pcm_name(handle));
			fprintf(stderr, "         please, try the plug plugin %s\n",
				plugex);
		}
	}
	rate = hwparams.rate;
	if (buffer_time == 0 && buffer_frames == 0) {
		err = snd_pcm_hw_params_get_buffer_time_max(params,
							    &buffer_time, 0);
		assert(err >= 0);
		if (buffer_time > 500000)
			buffer_time = 500000;
	}
	if (period_time == 0 && period_frames == 0) {
		if (buffer_time > 0)
			period_time = buffer_time / 4;
		else
			period_frames = buffer_frames / 4;
	}
	if (period_time > 0)
		err = snd_pcm_hw_params_set_period_time_near(handle, params,
							     &period_time, 0);
	else
		err = snd_pcm_hw_params_set_period_size_near(handle, params,
							     &period_frames, 0);
	assert(err >= 0);
	if (buffer_time > 0) {
		err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
							     &buffer_time, 0);
	} else {
		err = snd_pcm_hw_params_set_buffer_size_near(handle, params,
							     &buffer_frames);
	}
	assert(err >= 0);
	err = snd_pcm_hw_params(handle, params);
	if (err < 0) {
		error("Unable to install hw params:");
		snd_pcm_hw_params_dump(params, log);
		exit(EXIT_FAILURE);
	}
	snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
	snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
	if (chunk_size == buffer_size) {
		error("Can't use period equal to buffer size (%lu == %lu)",
		      chunk_size, buffer_size);
		exit(EXIT_FAILURE);
	}
	snd_pcm_sw_params_current(handle, swparams);
	if (avail_min < 0)
		n = chunk_size;
	else
		n = (double) rate * avail_min / 1000000;
	err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);
	if (err < 0) {
		error("Setting sw params failed\n");
	}

	/* round up to closest transfer boundary */
	n = buffer_size;
	if (start_delay <= 0) {
		start_threshold = n + (double) rate * start_delay / 1000000;
	} else
		start_threshold = (double) rate * start_delay / 1000000;
	if (start_threshold < 1)
		start_threshold = 1;
	if (start_threshold > n)
		start_threshold = n;
	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
	assert(err >= 0);
	if (stop_delay <= 0) 
		stop_threshold = buffer_size + (double) rate * stop_delay / 1000000;
	else
		stop_threshold = (double) rate * stop_delay / 1000000;
	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
	assert(err >= 0);

	if (snd_pcm_sw_params(handle, swparams) < 0) {
		error("unable to install sw params:");
		snd_pcm_sw_params_dump(swparams, log);
		exit(EXIT_FAILURE);
	}

	if (verbose)
		snd_pcm_dump(handle, log);

	bits_per_sample = snd_pcm_format_physical_width(hwparams.format);
	bits_per_frame = bits_per_sample * hwparams.channels;
	chunk_bytes = chunk_size * bits_per_frame / 8;
	audiobuf = realloc(audiobuf, chunk_bytes);
	if (audiobuf == NULL) {
		error("not enough memory");
		exit(EXIT_FAILURE);
	}
	// fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size);

	/* stereo VU-meter isn't always available... */
	if (vumeter == VUMETER_STEREO) {
		if (hwparams.channels != 2 || !interleaved || verbose > 2)
			vumeter = VUMETER_MONO;
	}

	/* show mmap buffer arragment */
	if (mmap_flag && verbose) {
		const snd_pcm_channel_area_t *areas;
		snd_pcm_uframes_t offset;
		int i;
		err = snd_pcm_mmap_begin(handle, &areas, &offset, &chunk_size);
		if (err < 0) {
			error("snd_pcm_mmap_begin problem: %s", snd_strerror(err));
			exit(EXIT_FAILURE);
		}
		for (i = 0; i < hwparams.channels; i++)
			fprintf(stderr, "mmap_area[%i] = %p,%u,%u (%u)\n", i, areas[i].addr, areas[i].first, areas[i].step, snd_pcm_format_physical_width(hwparams.format));
		/* not required, but for sure */
		snd_pcm_mmap_commit(handle, offset, 0);
	}

	buffer_frames = buffer_size;	/* for position test */
}
Example #29
0
int ai_alsa_setup(audio_in_t *ai)
{
    snd_pcm_hw_params_t *params;
    snd_pcm_sw_params_t *swparams;
    snd_pcm_uframes_t buffer_size, period_size;
    int err;
    int dir;
    unsigned int rate;

    snd_pcm_hw_params_alloca(&params);
    snd_pcm_sw_params_alloca(&swparams);

    err = snd_pcm_hw_params_any(ai->alsa.handle, params);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Broken configuration for this PCM: no configurations available.\n");
	return -1;
    }

    err = snd_pcm_hw_params_set_access(ai->alsa.handle, params,
				       SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Access type not available.\n");
	return -1;
    }

    err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Sample format not available.\n");
	return -1;
    }

    err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels);
    if (err < 0) {
	snd_pcm_hw_params_get_channels(params, &ai->channels);
	mp_tmsg(MSGT_TV, MSGL_ERR, "Channel count not available - reverting to default: %d\n",
	       ai->channels);
    } else {
	ai->channels = ai->req_channels;
    }

    dir = 0;
    rate = ai->req_samplerate;
    err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set samplerate.\n");
    }
    ai->samplerate = rate;

    dir = 0;
    ai->alsa.buffer_time = 1000000;
    err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params,
						 &ai->alsa.buffer_time, &dir);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set buffer time.\n");
    }

    dir = 0;
    ai->alsa.period_time = ai->alsa.buffer_time / 4;
    err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params,
						 &ai->alsa.period_time, &dir);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set period time.\n");
    }

    err = snd_pcm_hw_params(ai->alsa.handle, params);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install hardware parameters: %s", snd_strerror(err));
	snd_pcm_hw_params_dump(params, ai->alsa.log);
	return -1;
    }

    dir = -1;
    snd_pcm_hw_params_get_period_size(params, &period_size, &dir);
    snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
    ai->alsa.chunk_size = period_size;
    if (period_size == buffer_size) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Can't use period equal to buffer size (%u == %lu)\n", ai->alsa.chunk_size, (long)buffer_size);
	return -1;
    }

    snd_pcm_sw_params_current(ai->alsa.handle, swparams);
    err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size);

    err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0);
    err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size);

    if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install software parameters:\n");
	snd_pcm_sw_params_dump(swparams, ai->alsa.log);
	return -1;
    }

    if (mp_msg_test(MSGT_TV, MSGL_V)) {
	snd_pcm_dump(ai->alsa.handle, ai->alsa.log);
    }

    ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
    ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels;
    ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8;
    ai->samplesize = ai->alsa.bits_per_sample;
    ai->bytes_per_sample = ai->alsa.bits_per_sample/8;

    return 0;
}
Example #30
0
    bool open()
    {
        // Open the Alsa playback device.
        int err=-1,count=0;
        unsigned int        freakuency = frequency;

        while((count < 5) && (err < 0)) {
            err = snd_pcm_open
                  ( &handle,  ALSA_OUTPUT_NAME, SND_PCM_STREAM_PLAYBACK, 0 );

            if(err < 0) {
                count++;
                qWarning()<<"QAudioOutput::open() err="<<err<<", count="<<count;
            }
        }
        if (( err < 0)||(handle == 0)) {
            qWarning( "QAudioOuput: snd_pcm_open: error %d", err );
            return false;
        }
        snd_pcm_nonblock( handle, 0 );

        // Set the desired HW parameters.
        snd_pcm_hw_params_t *hwparams;
        snd_pcm_hw_params_alloca( &hwparams );

        err = snd_pcm_hw_params_any( handle, hwparams );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_any: err %d", err);
            return false;
        }

        err = snd_pcm_hw_params_set_access( handle, hwparams, access );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_access: err %d", err);
            return false;
        }

        err = snd_pcm_hw_params_set_format( handle, hwparams,
             ( bitsPerSample == 16 ? SND_PCM_FORMAT_S16
                                   : SND_PCM_FORMAT_U8 ) );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_format: err %d", err);
            return false;
        }

        err = snd_pcm_hw_params_set_channels
            ( handle, hwparams, (unsigned int)channels );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_channels: err %d", err);
            return false;
        }

        err = snd_pcm_hw_params_set_rate_near
            ( handle, hwparams, &freakuency, 0 );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_rate_near: err %d", err);
            return false;
        }

#ifndef ALSA_BUFFER_SIZE
        err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err %d",err);
        }
        err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_get_buffer_size: err %d",err);
        }
#else
        buffer_size = ALSA_BUFFER_SIZE;
        err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err %d",err);
        }
#endif

#ifndef ALSA_PERIOD_SIZE
        period_time = buffer_time/4;
        err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_period_time_near: err %d",err);
        }
#else
        period_size = ALSA_PERIOD_SIZE;
        err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, 0);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_period_size_near: err %d",err);
        }
#endif

        err = snd_pcm_hw_params(handle, hwparams);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params: err %d", err);
            return false;
        }

        int                  dir;
        unsigned int         vval, vval2;
        snd_pcm_access_t     val;
        snd_pcm_format_t     fval;
        snd_pcm_subformat_t  sval;


        qLog(QAudioOutput) << "PCM handle name =" << snd_pcm_name(handle);
        qLog(QAudioOutput) << "PCM state =" << snd_pcm_state_name(snd_pcm_state(handle));
        snd_pcm_hw_params_get_access(hwparams,&val);
        vval = (unsigned int)val;
        if ( (int)vval != (int)access ) {
            qWarning( "QAudioInput: access type not set, want %s got %s",
                    snd_pcm_access_name((snd_pcm_access_t)access),
                    snd_pcm_access_name((snd_pcm_access_t)vval) );
            access = (snd_pcm_access_t)vval;
        }
        qLog(QAudioOutput) << "access type =" << snd_pcm_access_name((snd_pcm_access_t)vval);
        snd_pcm_hw_params_get_format(hwparams, &fval);
        vval = (unsigned int)fval;
        if ( (int)vval != (int)format ) {
            qWarning( "QAudioInput: format type not set, want %s got %s",
                    snd_pcm_format_name((snd_pcm_format_t)format),
                    snd_pcm_format_name((snd_pcm_format_t)vval) );
            format = (snd_pcm_format_t)vval;
        }
        qLog(QAudioOutput) << QString("format = '%1' (%2)").arg(snd_pcm_format_name((snd_pcm_format_t)vval))
            .arg(snd_pcm_format_description((snd_pcm_format_t)vval))
            .toLatin1().constData();
        snd_pcm_hw_params_get_subformat(hwparams,&sval);
        vval = (unsigned int)sval;
        qLog(QAudioOutput) << QString("subformat = '%1' (%2)").arg(snd_pcm_subformat_name((snd_pcm_subformat_t)vval))
            .arg(snd_pcm_subformat_description((snd_pcm_subformat_t)vval))
            .toLatin1().constData();
        snd_pcm_hw_params_get_channels(hwparams, &vval);
        if ( (int)vval != (int)channels ) {
            qWarning( "QAudioInput: channels type not set, want %d got %d",channels,vval);
            channels = vval;
        }
        qLog(QAudioOutput) << "channels =" << vval;
        snd_pcm_hw_params_get_rate(hwparams, &vval, &dir);
        if ( (int)vval != (int)frequency ) {
            qWarning( "QAudioInput: frequency type not set, want %d got %d",frequency,vval);
            frequency = vval;
        }
        qLog(QAudioOutput) << "rate =" << vval << "bps";
        snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
        qLog(QAudioOutput) << "period time =" << period_time << "us";
        snd_pcm_hw_params_get_period_size(hwparams,&period_size, &dir);
        qLog(QAudioOutput) << "period size =" << (int)period_size << "frames";
        qLog(QAudioOutput) << "buffer time =" << (int)buffer_time << "us";
        qLog(QAudioOutput) << "buffer size =" << (int)buffer_size << "frames";
        snd_pcm_hw_params_get_periods(hwparams, &vval, &dir);
        periods = vval;
        qLog(QAudioOutput) << "periods per buffer =" << vval << "frames";
        snd_pcm_hw_params_get_rate_numden(hwparams, &vval, &vval2);
        qLog(QAudioOutput) << QString("exact rate = %1/%2 bps").arg(vval).arg(vval2).toLatin1().constData();
        vval = snd_pcm_hw_params_get_sbits(hwparams);
        qLog(QAudioOutput) << "significant bits =" << vval;
        vval = snd_pcm_hw_params_is_batch(hwparams);
        qLog(QAudioOutput) << "is batch =" << vval;
        vval = snd_pcm_hw_params_is_block_transfer(hwparams);
        qLog(QAudioOutput) << "is block transfer =" << vval;
        vval = snd_pcm_hw_params_is_double(hwparams);
        qLog(QAudioOutput) << "is double =" << vval;
        vval = snd_pcm_hw_params_is_half_duplex(hwparams);
        qLog(QAudioOutput) << "is half duplex =" << vval;
        vval = snd_pcm_hw_params_is_joint_duplex(hwparams);
        qLog(QAudioOutput) << "is joint duplex =" << vval;
        vval = snd_pcm_hw_params_can_overrange(hwparams);
        qLog(QAudioOutput) << "can overrange =" << vval;
        vval = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams);
        qLog(QAudioOutput) << "can mmap =" << vval;
        vval = snd_pcm_hw_params_can_pause(hwparams);
        qLog(QAudioOutput) << "can pause =" << vval;
        vval = snd_pcm_hw_params_can_resume(hwparams);
        qLog(QAudioOutput) << "can resume =" << vval;
        vval = snd_pcm_hw_params_can_sync_start(hwparams);
        qLog(QAudioOutput) << "can sync start =" << vval;

        // Set the desired SW parameters.
        snd_pcm_sw_params_t *swparams;
        snd_pcm_sw_params_alloca(&swparams);
        err = snd_pcm_sw_params_current(handle, swparams);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params_current: err %d",err);
        }
        err = snd_pcm_sw_params_set_start_threshold(handle,swparams,buffer_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params_set_start_threshold: err %d",err);
        }
        err = snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params_set_stop_threshold: err %d",err);
        }
        err = snd_pcm_sw_params_set_avail_min(handle, swparams,period_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params_set_avail_min: err %d",err);
        }
        err = snd_pcm_sw_params(handle, swparams);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params: err %d",err);
        }

        // Prepare for audio output.
        snd_pcm_prepare( handle );

        return true;
    }