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; }
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; }
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(¶ms); 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); }
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; }
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; }
static int set_hwparams (GstAlsaSink * alsa) { guint rrate; gint err; snd_pcm_hw_params_t *params; guint period_time, buffer_time; snd_pcm_hw_params_malloc (¶ms); GST_DEBUG_OBJECT (alsa, "Negotiating to %d channels @ %d Hz (format = %s) " "SPDIF (%d)", alsa->channels, alsa->rate, snd_pcm_format_name (alsa->format), alsa->iec958); /* start with requested values, if we cannot configure alsa for those values, * we set these values to -1, which will leave the default alsa values */ buffer_time = alsa->buffer_time; period_time = alsa->period_time; retry: /* choose all parameters */ CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config); /* set the interleaved read/write format */ CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access), wrong_access); /* set the sample format */ if (alsa->iec958) { /* Try to use big endian first else fallback to le and swap bytes */ if (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format) < 0) { alsa->format = SND_PCM_FORMAT_S16_LE; alsa->need_swap = TRUE; GST_DEBUG_OBJECT (alsa, "falling back to little endian with swapping"); } else { alsa->need_swap = FALSE; } } CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format), no_sample_format); /* set the count of channels */ CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels), no_channels); /* set the stream rate */ rrate = alsa->rate; CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL), no_rate); #ifndef GST_DISABLE_GST_DEBUG /* get and dump some limits */ { guint min, max; snd_pcm_hw_params_get_buffer_time_min (params, &min, NULL); snd_pcm_hw_params_get_buffer_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u", alsa->buffer_time, min, max); snd_pcm_hw_params_get_period_time_min (params, &min, NULL); snd_pcm_hw_params_get_period_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u", alsa->period_time, min, max); snd_pcm_hw_params_get_periods_min (params, &min, NULL); snd_pcm_hw_params_get_periods_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); } #endif /* now try to configure the buffer time and period time, if one * of those fail, we fall back to the defaults and emit a warning. */ if (buffer_time != -1 && !alsa->iec958) { /* set the buffer time */ if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, &buffer_time, NULL)) < 0) { GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set buffer time %i for playback: %s", buffer_time, snd_strerror (err))); /* disable buffer_time the next round */ buffer_time = -1; goto retry; } GST_DEBUG_OBJECT (alsa, "buffer time %u", buffer_time); } if (period_time != -1 && !alsa->iec958) { /* set the period time */ if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params, &period_time, NULL)) < 0) { GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set period time %i for playback: %s", period_time, snd_strerror (err))); /* disable period_time the next round */ period_time = -1; goto retry; } GST_DEBUG_OBJECT (alsa, "period time %u", period_time); } /* Set buffer size and period size manually for SPDIF */ if (G_UNLIKELY (alsa->iec958)) { snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE; snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE; CHECK (snd_pcm_hw_params_set_buffer_size_near (alsa->handle, params, &buffer_size), buffer_size); CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params, &period_size, NULL), period_size); } /* write the parameters to device */ CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); /* now get the configured values */ CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size), buffer_size); CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, NULL), period_size); GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size, alsa->period_size); snd_pcm_hw_params_free (params); return 0; /* ERRORS */ no_config: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Broken configuration for playback: no configurations available: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } wrong_access: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Access type not available for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_sample_format: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Sample format not available for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_channels: { gchar *msg = NULL; if ((alsa->channels) == 1) msg = g_strdup (_("Could not open device for playback in mono mode.")); if ((alsa->channels) == 2) msg = g_strdup (_("Could not open device for playback in stereo mode.")); if ((alsa->channels) > 2) msg = g_strdup_printf (_ ("Could not open device for playback in %d-channel mode."), alsa->channels); GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg), ("%s", snd_strerror (err))); g_free (msg); snd_pcm_hw_params_free (params); return err; } no_rate: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Rate %iHz not available for playback: %s", alsa->rate, snd_strerror (err))); return err; } buffer_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get buffer size for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } period_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get period size for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } set_hw_params: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set hw params for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } }
static 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; }
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; }
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"); }
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; }
/************************************************************************** * 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; }
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; }
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; }
/* ------- PCM INITS --------------------------------- */ static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params,int *chs) { #ifndef ALSAAPI9 unsigned int rrate; int err, dir; int channels_allocated = 0; /* choose all parameters */ err = snd_pcm_hw_params_any(handle, params); if (err < 0) { check_error(err,"Broken configuration: no configurations available"); return err; } /* set the nointerleaved read/write format */ err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); if (err >= 0) { #ifdef ALSAMM_DEBUG if(sys_verbose) post("Access type %s available","SND_PCM_ACCESS_MMAP_NONINTERLEAVED"); #endif } else{ check_error(err,"No Accesstype SND_PCM_ACCESS_MMAP_NONINTERLEAVED"); return err; } /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, params, ALSAMM_FORMAT); if (err < 0) { check_error(err,"Sample format not available for playback"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("Setting format to %s",snd_pcm_format_name(ALSAMM_FORMAT)); #endif /* first check samplerate since channels numbers are samplerate dependent (double speed) */ /* set the stream rate */ rrate = alsamm_sr; #ifdef ALSAMM_DEBUG if(sys_verbose) post("Samplerate request: %i Hz",rrate); #endif dir=-1; err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, &dir); if (err < 0) { check_error(err,"Rate not available"); return err; } if (rrate != alsamm_sr) { post("Warning: rate %iHz doesn't match requested %iHz", rrate,alsamm_sr); alsamm_sr = rrate; } else if(sys_verbose) post("Samplerate is set to %iHz",alsamm_sr); /* Info on channels */ { int maxchs,minchs,channels = *chs; if((err = snd_pcm_hw_params_get_channels_max(params, (unsigned int *)&maxchs)) < 0){ check_error(err,"Getting channels_max not available"); return err; } if((err = snd_pcm_hw_params_get_channels_min(params, (unsigned int *)&minchs)) < 0){ check_error(err,"Getting channels_min not available"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("Getting channels:min=%d, max= %d for request=%d",minchs,maxchs,channels); #endif if(channels < 0)channels=maxchs; if(channels > maxchs)channels = maxchs; if(channels < minchs)channels = minchs; if(channels != *chs) post("requested channels=%d but used=%d",*chs,channels); *chs = channels; #ifdef ALSAMM_DEBUG if(sys_verbose) post("trying to use channels: %d",channels); #endif } /* set the count of channels */ err = snd_pcm_hw_params_set_channels(handle, params, *chs); if (err < 0) { check_error(err,"Channels count not available"); return err; } /* testing for channels */ if((err = snd_pcm_hw_params_get_channels(params,(unsigned int *)chs)) < 0) check_error(err,"Get channels not available"); #ifdef ALSAMM_DEBUG else if(sys_verbose) post("When setting channels count and got %d",*chs); #endif /* if buffersize is set use this instead buffertime */ if(alsamm_buffersize > 0){ #ifdef ALSAMM_DEBUG if(sys_verbose) post("hw_params: ask for max buffersize of %d samples", (unsigned int) alsamm_buffersize ); #endif alsamm_buffer_size = alsamm_buffersize; err = snd_pcm_hw_params_set_buffer_size_near(handle, params, (unsigned long *)&alsamm_buffer_size); if (err < 0) { check_error(err,"Unable to set max buffer size"); return err; } } else{ if(alsamm_buffertime <= 0) /* should never happen, but use 20ms */ alsamm_buffertime = 20000; #ifdef ALSAMM_DEBUG if(sys_verbose) post("hw_params: ask for max buffertime of %d ms", (unsigned int) (alsamm_buffertime*0.001) ); #endif err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &alsamm_buffertime, &dir); if (err < 0) { check_error(err,"Unable to set max buffer time"); return err; } } err = snd_pcm_hw_params_get_buffer_time(params, (unsigned int *)&alsamm_buffertime, &dir); if (err < 0) { check_error(err,"Unable to get buffer time"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("hw_params: got buffertime to %f ms", (float) (alsamm_buffertime*0.001)); #endif err = snd_pcm_hw_params_get_buffer_size(params, (unsigned long *)&alsamm_buffer_size); if (err < 0) { check_error(err,"Unable to get buffer size"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("hw_params: got buffersize to %d samples",(int) alsamm_buffer_size); #endif err = snd_pcm_hw_params_get_period_size(params, (unsigned long *)&alsamm_period_size, &dir); if (err > 0) { check_error(err,"Unable to get period size"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("Got period size of %d", (int) alsamm_period_size); #endif { unsigned int pmin,pmax; err = snd_pcm_hw_params_get_periods_min(params, &pmin, &dir); if (err > 0) { check_error(err,"Unable to get period size"); return err; } err = snd_pcm_hw_params_get_periods_min(params, &pmax, &dir); if (err > 0) { check_error(err,"Unable to get period size"); return err; } /* use maximum of periods */ if( alsamm_periods <= 0) alsamm_periods = pmax; alsamm_periods = (alsamm_periods > pmax)?pmax:alsamm_periods; alsamm_periods = (alsamm_periods < pmin)?pmin:alsamm_periods; err = snd_pcm_hw_params_set_periods(handle, params, alsamm_periods, dir); if (err > 0) { check_error(err,"Unable to set periods"); return err; } err = snd_pcm_hw_params_get_periods(params, &pmin, &dir); if (err > 0) { check_error(err,"Unable to get periods"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("Got periods of %d, where periodsmin=%d, periodsmax=%d", alsamm_periods,pmin,pmax); #endif } /* write the parameters to device */ err = snd_pcm_hw_params(handle, params); if (err < 0) { check_error(err,"Unable to set hw params"); return err; } #endif /* ALSAAPI9 */ return 0; }
static int set_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(¶ms); /* 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; }
/*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; }
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, ¶m->chunk_size, 0); snd_pcm_hw_params_get_buffer_size(hwparams, ¶m->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; }
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; }
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(¶ms); 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); }
/*------------------------------------------------------------------------------ * 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; }
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(¶ms)); 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; }
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(¶ms); 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 */ }
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, ¶m); 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, ¶m); 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, ¶m, 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, ¶m, &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, ¶m, 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, ¶m, 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; }
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; }
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(¶ms); 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; }
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 (¶ms); //> //<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; }