Esempio n. 1
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;
}
Esempio n. 2
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;
}
Esempio n. 3
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);
}
Esempio n. 5
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;
}
Esempio n. 6
0
static int capture(lua_State *lstate) {
	char *card;
	snd_pcm_sw_params_t *sparams;
	int ret, dir, i;
	snd_pcm_format_t f, format;
	unsigned int rate, buffer_time;
	if (rbuf == NULL) {
		rbuf = new_ringbuf(jack_sr, CHANNELS, BUFSECS,
					0.333, 0.667);
		}
	getstring(lstate, "card", &card);
	lua_pop(lstate, 1);
	for (i = 0; i < 20; i++) {
		ret = snd_pcm_open(&handle, card, SND_PCM_STREAM_CAPTURE, 0);
		if (ret < 0) {
			logmsg("can't open %s (%s)\n", card, snd_strerror(ret));
			}
		else {
			break;
			}
		}
	free(card);
	if (ret < 0) return 0;
	if (hparams != NULL) snd_pcm_hw_params_free(hparams);
	snd_pcm_hw_params_malloc(&hparams);
	snd_pcm_hw_params_any(handle, hparams);
	for (f = format = 0; f < SND_PCM_FORMAT_LAST; f++) {
		ret = snd_pcm_hw_params_test_format(handle, hparams, f);
		if (ret == 0) {
			logmsg("- %s\n", snd_pcm_format_name(f));
			format = f;
			}
		}
	ret = snd_pcm_hw_params_set_access(handle, hparams,
				SND_PCM_ACCESS_RW_INTERLEAVED);
	if (ret < 0) {
		logmsg("access %s\n", snd_strerror(ret));
		}
	ret = snd_pcm_hw_params_set_format(handle, hparams, format);
	logmsg("format: %s\n", snd_pcm_format_description(format));
	if (ret < 0) {
		logmsg("format error %s\n", snd_strerror(ret));
		}
	snd_pcm_hw_params_get_buffer_time_max(hparams, &buffer_time, 0);
	rate = jack_sr;
	ret = snd_pcm_hw_params_set_rate(handle, hparams, rate, 0);
logmsg("rate %d\n", rate);
	if (ret < 0) logmsg("rate error %s\n", snd_strerror(ret));
	snd_pcm_hw_params_set_channels(handle, hparams, CHANNELS);
	blocksize = BLOCKSIZE;
	snd_pcm_hw_params_set_period_size(handle, hparams, blocksize, 0);
logmsg("period %ld\n", blocksize);
	snd_pcm_hw_params_set_buffer_time_near(handle, hparams, &buffer_time, &dir);
logmsg("buffer time %u\n", buffer_time);
	if ((ret = snd_pcm_hw_params(handle, hparams)) < 0) {
		logmsg("can't set hardware: %s\n",
			snd_strerror(ret));
		return 0;
		}
	else logmsg("hardware configd\n");
	snd_pcm_sw_params_malloc(&sparams);
	snd_pcm_sw_params_current(handle, sparams);
	snd_pcm_sw_params_set_avail_min(handle, sparams, blocksize);
	snd_pcm_sw_params_set_start_threshold(handle, sparams, 0U);
	if ((ret = snd_pcm_sw_params(handle, sparams)) < 0) {
		logmsg("can't set software: %s\n",
			snd_strerror(ret));
		}
	else logmsg("software configd\n");
	snd_pcm_sw_params_free(sparams);
	pthread_create(&thread_id, NULL, dev_thread, NULL);
	return 0;
	}
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;
}
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;
}
Esempio n. 9
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;
    }
}
Esempio n. 10
0
static snd_pcm_t *alsa_open(snd_pcm_t **pcm_handle, int stream_type,
        snd_pcm_uframes_t *buffer_size) {
    char                *pcm_name = "chumix";
    snd_pcm_hw_params_t *hwparams;
    snd_pcm_sw_params_t *swparams;
    unsigned int         buffer_time;
    int                  status;
    snd_pcm_uframes_t    xfer_align;


    // Open the device.  Experimenting with duplex mode.
    fprintf(stderr, "Opening PCM device\n");
    status = snd_pcm_open(pcm_handle, pcm_name,
                          stream_type, 0);
    if(status < 0) {
        fprintf(stderr, "Unable to open audio device: %s\n",
                snd_strerror(status));
        goto error;
    }


    // Determine what the hardware can do.
    fprintf(stderr, "Allocating hw params\n");
    snd_pcm_hw_params_malloc(&hwparams);
    status = snd_pcm_hw_params_any(*pcm_handle, hwparams);
    if(status < 0) {
        fprintf(stderr, "Unable to get hardware parameters: %s\n",
                snd_strerror(status));
        goto error;
    }


    // Set up interleaved audio.
    fprintf(stderr, "Setting up interleaved audio\n");
    status = snd_pcm_hw_params_set_access(*pcm_handle, hwparams,
                                          SND_PCM_ACCESS_RW_INTERLEAVED);
    if(status < 0) {
        fprintf(stderr, "Unable to set interleaved mode: %s\n",
                snd_strerror(status));
        goto error;
    }


    // Set the audio format.
    fprintf(stderr, "Setting format\n");
    status = snd_pcm_hw_params_set_format(*pcm_handle, hwparams,
                                          SND_PCM_FORMAT_S16_LE);
    if(status<0) {
        fprintf(stderr, "Unable to set audio format: %s\n",
                snd_strerror(status));
        goto error;
    }


    // Set stereo audio.
    fprintf(stderr, "Setting channels\n");
    status = snd_pcm_hw_params_set_channels(*pcm_handle, hwparams, 2);
    if(status<0) {
        fprintf(stderr, "Unable to set stereo mode: %s\n",
                snd_strerror(status));
        goto error;
    }


    // Set sample rate.
    fprintf(stderr, "Setting audio rate\n");
    int rate = 44100;
    status = snd_pcm_hw_params_set_rate_near(*pcm_handle, hwparams,
                                             &rate, NULL);
    if(status<0) {
        fprintf(stderr, "Unable to set sample rate to 44100: %s\n",
                snd_strerror(status));
        goto error;
    }

    // Set buffer time to a reasonable value.
    // Probably won't work for playback, as it's fixed in /etc/asound.conf
    buffer_time = BUFFER_TIME;
    status = snd_pcm_hw_params_set_buffer_time_near(*pcm_handle, hwparams,
                                                         &buffer_time, 0);
    snd_pcm_hw_params_get_buffer_size(hwparams, buffer_size);


    // Write the settings out to the audio card.
    fprintf(stderr, "Setting hw params\n");
    status = snd_pcm_hw_params(*pcm_handle, hwparams);
    if(status<0) {
        fprintf(stderr, "Unable to set audio parameters: %s\n",
                snd_strerror(status));
        goto error;
    }

    snd_pcm_hw_params_free(hwparams);

    status = snd_pcm_prepare(*pcm_handle);
    if(status<0) {
        fprintf(stderr, "Unable to prepare audio device: %s\n",
                snd_strerror(status));
        goto error;
    }

    return *pcm_handle;

error:
    if(*pcm_handle) {
        snd_pcm_drain(*pcm_handle);
        snd_pcm_close(*pcm_handle);
    }
    return NULL;
}
Esempio n. 11
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;
}
Esempio n. 12
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");
}
Esempio n. 13
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;
}
Esempio n. 14
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;
}
Esempio n. 15
0
static RD_BOOL
alsa_set_format(snd_pcm_t * pcm, RD_WAVEFORMATEX * pwfx)
{
	snd_pcm_hw_params_t *hwparams = NULL;
	int err;
	unsigned int buffertime;
	short samplewidth;
	int audiochannels;
	unsigned int rate;

	samplewidth = pwfx->wBitsPerSample / 8;

	if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
	{
		error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
		return False;
	}

	if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0)
	{
		error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));
		return False;
	}

	if ((err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
	{
		error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));
		return False;
	}

	if (pwfx->wBitsPerSample == 16)
	{
		if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
		{
			error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
			return False;
		}
	}
	else
	{
		if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S8)) < 0)
		{
			error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
			return False;
		}
	}

#if 0
	if ((err = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 1)) < 0)
	{
		error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));
		return False;
	}
#endif

	rate = pwfx->nSamplesPerSec;
	if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0)
	{
		error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));
		return False;
	}

	audiochannels = pwfx->nChannels;
	if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams, pwfx->nChannels)) < 0)
	{
		error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));
		return False;
	}


	buffertime = 500000;	/* microseconds */
	if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams, &buffertime, 0)) < 0)
	{
		error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));
		return False;
	}

	if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0)
	{
		error("snd_pcm_hw_params: %s\n", snd_strerror(err));
		return False;
	}

	snd_pcm_hw_params_free(hwparams);

	if ((err = snd_pcm_prepare(pcm)) < 0)
	{
		error("snd_pcm_prepare: %s\n", snd_strerror(err));
		return False;
	}

	reopened = True;

	return True;
}
Esempio n. 16
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;
}
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;
}
Esempio n. 18
0
/* ------- PCM INITS --------------------------------- */
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params,int *chs)
{
#ifndef ALSAAPI9
  unsigned int rrate;
  int err, dir;
  int channels_allocated = 0;

  /* choose all parameters */
  err = snd_pcm_hw_params_any(handle, params);
  if (err < 0) {
    check_error(err,"Broken configuration: no configurations available");
    return err;
  }

  /* set the nointerleaved read/write format */
  err = snd_pcm_hw_params_set_access(handle, params,
                                     SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
  if (err >= 0) {
#ifdef ALSAMM_DEBUG
    if(sys_verbose)
      post("Access type %s available","SND_PCM_ACCESS_MMAP_NONINTERLEAVED");
#endif
  }
  else{
    check_error(err,"No Accesstype SND_PCM_ACCESS_MMAP_NONINTERLEAVED");
    return err;
  }

  /* set the sample format */
  err = snd_pcm_hw_params_set_format(handle, params, ALSAMM_FORMAT);
  if (err < 0) {
    check_error(err,"Sample format not available for playback");
    return err;
  }

#ifdef ALSAMM_DEBUG
  if(sys_verbose)
    post("Setting format to %s",snd_pcm_format_name(ALSAMM_FORMAT));
#endif

  /* first check samplerate since channels numbers
     are samplerate dependent (double speed) */
  /* set the stream rate */

  rrate = alsamm_sr;

#ifdef ALSAMM_DEBUG
  if(sys_verbose)
    post("Samplerate request: %i Hz",rrate);
#endif

  dir=-1;
  err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, &dir);
  if (err < 0) {
    check_error(err,"Rate not available");
    return err;
  }

  if (rrate != alsamm_sr) {
    post("Warning: rate %iHz doesn't match requested %iHz", rrate,alsamm_sr);
    alsamm_sr = rrate;
  }
  else
    if(sys_verbose)
      post("Samplerate is set to %iHz",alsamm_sr);

  /* Info on channels */
  {
    int maxchs,minchs,channels = *chs;

    if((err = snd_pcm_hw_params_get_channels_max(params,
        (unsigned int *)&maxchs)) < 0){
      check_error(err,"Getting channels_max not available");
      return err;
    }
    if((err = snd_pcm_hw_params_get_channels_min(params,
        (unsigned int *)&minchs)) < 0){
      check_error(err,"Getting channels_min not available");
      return err;
    }

#ifdef ALSAMM_DEBUG
    if(sys_verbose)
      post("Getting channels:min=%d, max= %d for request=%d",minchs,maxchs,channels);
#endif
    if(channels < 0)channels=maxchs;
    if(channels > maxchs)channels = maxchs;
    if(channels < minchs)channels = minchs;

    if(channels != *chs)
      post("requested channels=%d but used=%d",*chs,channels);

    *chs = channels;
#ifdef ALSAMM_DEBUG
    if(sys_verbose)
      post("trying to use channels: %d",channels);
#endif
  }

  /* set the count of channels */
  err = snd_pcm_hw_params_set_channels(handle, params, *chs);
  if (err < 0) {
    check_error(err,"Channels count not available");
    return err;
  }

  /* testing for channels */
  if((err = snd_pcm_hw_params_get_channels(params,(unsigned int *)chs)) < 0)
    check_error(err,"Get channels not available");
#ifdef ALSAMM_DEBUG
  else
    if(sys_verbose)
      post("When setting channels count and got %d",*chs);
#endif

  /* if buffersize is set use this instead buffertime */
  if(alsamm_buffersize > 0){

#ifdef ALSAMM_DEBUG
    if(sys_verbose)
      post("hw_params: ask for max buffersize of %d samples",
           (unsigned int) alsamm_buffersize );
#endif

    alsamm_buffer_size = alsamm_buffersize;

    err = snd_pcm_hw_params_set_buffer_size_near(handle, params,
        (unsigned long *)&alsamm_buffer_size);
    if (err < 0) {
      check_error(err,"Unable to set max buffer size");
      return err;
    }

  }
  else{
    if(alsamm_buffertime <= 0) /* should never happen, but use 20ms */
      alsamm_buffertime = 20000;

#ifdef ALSAMM_DEBUG
    if(sys_verbose)
      post("hw_params: ask for max buffertime of %d ms",
           (unsigned int) (alsamm_buffertime*0.001) );
#endif

    err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
        &alsamm_buffertime, &dir);
    if (err < 0) {
      check_error(err,"Unable to set max buffer time");
      return err;
    }
  }

  err = snd_pcm_hw_params_get_buffer_time(params,
    (unsigned int *)&alsamm_buffertime, &dir);
  if (err < 0) {
    check_error(err,"Unable to get buffer time");
    return err;
  }

#ifdef ALSAMM_DEBUG
  if(sys_verbose)
    post("hw_params: got buffertime to %f ms",
         (float) (alsamm_buffertime*0.001));
#endif

  err = snd_pcm_hw_params_get_buffer_size(params,
    (unsigned long *)&alsamm_buffer_size);
  if (err < 0) {
    check_error(err,"Unable to get buffer size");
    return err;
  }

#ifdef ALSAMM_DEBUG
  if(sys_verbose)
    post("hw_params: got  buffersize to %d samples",(int) alsamm_buffer_size);
#endif

  err = snd_pcm_hw_params_get_period_size(params,
    (unsigned long *)&alsamm_period_size, &dir);
  if (err > 0) {
    check_error(err,"Unable to get period size");
    return err;
  }

#ifdef ALSAMM_DEBUG
  if(sys_verbose)
    post("Got period size of %d", (int) alsamm_period_size);
#endif
  {
    unsigned int pmin,pmax;

    err = snd_pcm_hw_params_get_periods_min(params, &pmin, &dir);
    if (err > 0) {
      check_error(err,"Unable to get period size");
      return err;
    }
    err = snd_pcm_hw_params_get_periods_min(params, &pmax, &dir);
    if (err > 0) {
      check_error(err,"Unable to get period size");
      return err;
    }

    /* use maximum of periods */
    if( alsamm_periods <= 0)
      alsamm_periods = pmax;
    alsamm_periods = (alsamm_periods > pmax)?pmax:alsamm_periods;
    alsamm_periods = (alsamm_periods < pmin)?pmin:alsamm_periods;

    err = snd_pcm_hw_params_set_periods(handle, params, alsamm_periods, dir);
    if (err > 0) {
      check_error(err,"Unable to set periods");
      return err;
    }


    err = snd_pcm_hw_params_get_periods(params, &pmin, &dir);
    if (err > 0) {
      check_error(err,"Unable to get periods");
      return err;
    }
#ifdef ALSAMM_DEBUG
    if(sys_verbose)
      post("Got periods of %d, where periodsmin=%d, periodsmax=%d",
           alsamm_periods,pmin,pmax);
#endif
  }

  /* write the parameters to device */
  err = snd_pcm_hw_params(handle, params);
  if (err < 0) {
    check_error(err,"Unable to set hw params");
    return err;
  }
#endif /* ALSAAPI9 */
  return 0;
}
Esempio n. 19
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;
}
Esempio n. 20
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;
}
Esempio n. 21
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;
}
Esempio n. 22
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;
}
Esempio n. 23
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);
}
Esempio n. 24
0
/*------------------------------------------------------------------------------
 *  Open the audio source
 *----------------------------------------------------------------------------*/
bool
AlsaDspSource :: open ( void )                       throw ( Exception )
{
    unsigned int        u;
    snd_pcm_format_t    format;
    snd_pcm_hw_params_t *hwParams;

    if ( isOpen() ) {
        return false;
    }

    switch ( getBitsPerSample() ) {
        case 8:
            format = SND_PCM_FORMAT_S8;
            break;

        case 16:
            format = SND_PCM_FORMAT_S16;
            break;
            
        default:
            return false;
    }

    if (snd_pcm_open(&captureHandle, pcmName, SND_PCM_STREAM_CAPTURE, 0) < 0) {
        captureHandle = 0;
        return false;
    }

    if (snd_pcm_hw_params_malloc(&hwParams) < 0) {
        close();
        throw Exception( __FILE__, __LINE__, "can't alloc hardware "\
                        "parameter structure");
    }

    if (snd_pcm_hw_params_any(captureHandle, hwParams) < 0) {
        snd_pcm_hw_params_free(hwParams);
        close();
        throw Exception( __FILE__, __LINE__, "can't initialize hardware "\
                        "parameter structure");
    }

    if (snd_pcm_hw_params_set_access(captureHandle, hwParams,
                                     SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        snd_pcm_hw_params_free(hwParams);
        close();
        throw Exception( __FILE__, __LINE__, "can't set access type");
    }

    if (snd_pcm_hw_params_set_format(captureHandle, hwParams, format) < 0) {
        snd_pcm_hw_params_free(hwParams);
        close();
        throw Exception( __FILE__, __LINE__, "can't set sample format");
    }

    u = getSampleRate();
    if (snd_pcm_hw_params_set_rate_near(captureHandle, hwParams, &u, 0) < 0) {
        snd_pcm_hw_params_free(hwParams);
        close();
        throw Exception( __FILE__, __LINE__, "can't set sample rate", u);
    }

    u = getChannel();
    if (snd_pcm_hw_params_set_channels(captureHandle, hwParams, u) < 0) {
        snd_pcm_hw_params_free(hwParams);
        close();
        throw Exception( __FILE__, __LINE__, "can't set channels", u);
    }

    u = 4;
    if (snd_pcm_hw_params_set_periods_near(captureHandle, hwParams, &u, 0)
                                                                          < 0) {
        snd_pcm_hw_params_free(hwParams);
        close();
        throw Exception( __FILE__, __LINE__, "can't set interrupt frequency");
    }

    u = getBufferTime();
    if (snd_pcm_hw_params_set_buffer_time_near(captureHandle, hwParams, &u, 0)
                                                                          < 0) {
        snd_pcm_hw_params_free(hwParams);
        close();
        throw Exception( __FILE__, __LINE__, "can't set buffer size");
    }

    if (snd_pcm_hw_params(captureHandle, hwParams) < 0) {
        snd_pcm_hw_params_free(hwParams);
        close();
        throw Exception( __FILE__, __LINE__, "can't set hardware parameters");
    }

    snd_pcm_hw_params_free(hwParams);

    if (snd_pcm_prepare(captureHandle) < 0) {
        close();
        throw Exception( __FILE__, __LINE__, "can't prepare audio interface "\
                        "for use");
    }

    bytesPerFrame = getChannel() * getBitsPerSample() / 8;

    return true;
}
Esempio n. 25
0
static void *alsa_thread_init(const char *device,
      unsigned rate, unsigned latency)
{
   snd_pcm_uframes_t buffer_size;
   snd_pcm_format_t format;
   snd_pcm_hw_params_t *params    = NULL;
   snd_pcm_sw_params_t *sw_params = NULL;
   const char *alsa_dev           = device ? device : "default";
   unsigned latency_usec          = latency * 1000 / 2;
   unsigned channels              = 2;
   unsigned periods               = 4;
   alsa_thread_t            *alsa = (alsa_thread_t*)
      calloc(1, sizeof(alsa_thread_t));

   if (!alsa)
      return NULL;

   TRY_ALSA(snd_pcm_open(&alsa->pcm, alsa_dev, SND_PCM_STREAM_PLAYBACK, 0));

   TRY_ALSA(snd_pcm_hw_params_malloc(&params));
   alsa->has_float = alsathread_find_float_format(alsa->pcm, params);
   format = alsa->has_float ? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16;

   TRY_ALSA(snd_pcm_hw_params_any(alsa->pcm, params));
   TRY_ALSA(snd_pcm_hw_params_set_access(
            alsa->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED));
   TRY_ALSA(snd_pcm_hw_params_set_format(alsa->pcm, params, format));
   TRY_ALSA(snd_pcm_hw_params_set_channels(alsa->pcm, params, channels));
   TRY_ALSA(snd_pcm_hw_params_set_rate(alsa->pcm, params, rate, 0));

   TRY_ALSA(snd_pcm_hw_params_set_buffer_time_near(
            alsa->pcm, params, &latency_usec, NULL));
   TRY_ALSA(snd_pcm_hw_params_set_periods_near(
            alsa->pcm, params, &periods, NULL));

   TRY_ALSA(snd_pcm_hw_params(alsa->pcm, params));

   /* Shouldn't have to bother with this, 
    * but some drivers are apparently broken. */
   if (snd_pcm_hw_params_get_period_size(params, &alsa->period_frames, NULL))
      snd_pcm_hw_params_get_period_size_min(
            params, &alsa->period_frames, NULL);
   RARCH_LOG("ALSA: Period size: %d frames\n", (int)alsa->period_frames);
   if (snd_pcm_hw_params_get_buffer_size(params, &buffer_size))
      snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size);
   RARCH_LOG("ALSA: Buffer size: %d frames\n", (int)buffer_size);

   alsa->buffer_size = snd_pcm_frames_to_bytes(alsa->pcm, buffer_size);
   alsa->period_size = snd_pcm_frames_to_bytes(alsa->pcm, alsa->period_frames);

   TRY_ALSA(snd_pcm_sw_params_malloc(&sw_params));
   TRY_ALSA(snd_pcm_sw_params_current(alsa->pcm, sw_params));
   TRY_ALSA(snd_pcm_sw_params_set_start_threshold(
            alsa->pcm, sw_params, buffer_size / 2));
   TRY_ALSA(snd_pcm_sw_params(alsa->pcm, sw_params));

   snd_pcm_hw_params_free(params);
   snd_pcm_sw_params_free(sw_params);

   alsa->fifo_lock = slock_new();
   alsa->cond_lock = slock_new();
   alsa->cond = scond_new();
   alsa->buffer = fifo_new(alsa->buffer_size);
   if (!alsa->fifo_lock || !alsa->cond_lock || !alsa->cond || !alsa->buffer)
      goto error;

   alsa->worker_thread = sthread_create(alsa_worker_thread, alsa);
   if (!alsa->worker_thread)
   {
      RARCH_ERR("error initializing worker thread");
      goto error;
   }

   return alsa;

error:
   RARCH_ERR("ALSA: Failed to initialize...\n");
   if (params)
      snd_pcm_hw_params_free(params);

   if (sw_params)
      snd_pcm_sw_params_free(sw_params);

   alsa_thread_free(alsa);

   return NULL;
}
Esempio n. 26
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 */
}
Esempio n. 27
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;
}
Esempio n. 28
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;
    }
Esempio n. 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;
}
Esempio n. 30
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;
}