static void getparams_periods(snd_pcm_t *handle, snd_pcm_hw_params_t *params, unsigned int *usecs, unsigned int *count, const char *id) { unsigned min = 0, max = 0; snd_pcm_hw_params_get_periods_min(params, &min, 0); snd_pcm_hw_params_get_periods_max(params, &max, 0); if (min && max) { if (verbose) fprintf(error_fp, "alsa: %s periods range between %u and %u. Want: %u\n", id, min, max, *count); if (*count < min) *count = min; if (*count > max) *count = max; } min = max = 0; snd_pcm_hw_params_get_period_time_min(params, &min, 0); snd_pcm_hw_params_get_period_time_max(params, &max, 0); if (min && max) { if (verbose) fprintf(error_fp, "alsa: %s period time range between %u and %u. Want: %u\n", id, min, max, *usecs); if (*usecs < min) *usecs = min; if (*usecs > max) *usecs = max; } }
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; } }
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 = 0; int count=0; unsigned int freakuency=settings.frequency(); if (!settings.isValid()) { qWarning("QAudioOutput: open error, invalid format."); } else if (settings.frequency() <= 0) { qWarning("QAudioOutput: open error, invalid sample rate (%d).", settings.frequency()); } else { err = -1; } if (err == 0) { errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; return false; } QString dev = QString(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()); #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 ) { unsigned int maxBufferTime = 0; unsigned int minBufferTime = 0; unsigned int maxPeriodTime = 0; unsigned int minPeriodTime = 0; err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir); if ( err >= 0) err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir); if ( err >= 0) err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir); if ( err >= 0) err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir); if ( err < 0 ) { fatal = true; errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err); } else { if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) { #ifdef DEBUG_AUDIO qDebug()<<"defaults out of range"; qDebug()<<"pmin="<<minPeriodTime<<", pmax="<<maxPeriodTime<<", bmin="<<minBufferTime<<", bmax="<<maxBufferTime; #endif period_time = minPeriodTime; if (period_time*4 <= maxBufferTime) { // Use 4 periods if possible buffer_time = period_time*4; chunks = 4; } else if (period_time*2 <= maxBufferTime) { // Use 2 periods if possible buffer_time = period_time*2; chunks = 2; } else { qWarning()<<"QAudioOutput: alsa only supports single period!"; fatal = true; } #ifdef DEBUG_AUDIO qDebug()<<"used: buffer_time="<<buffer_time<<", period_time="<<period_time; #endif } } } 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 set_hwparams (GstAlsaSrc * alsa) { guint rrate; gint err; snd_pcm_hw_params_t *params; snd_pcm_hw_params_malloc (¶ms); /* choose all parameters */ CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config); /* set the interleaved read/write format */ CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access), wrong_access); /* set the sample format */ CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format), no_sample_format); /* set the count of channels */ CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels), no_channels); /* set the stream rate */ rrate = alsa->rate; CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL), no_rate); if (rrate != alsa->rate) goto rate_match; #ifndef GST_DISABLE_GST_DEBUG /* get and dump some limits */ { guint min, max; snd_pcm_hw_params_get_buffer_time_min (params, &min, NULL); snd_pcm_hw_params_get_buffer_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u", alsa->buffer_time, min, max); snd_pcm_hw_params_get_period_time_min (params, &min, NULL); snd_pcm_hw_params_get_period_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u", alsa->period_time, min, max); snd_pcm_hw_params_get_periods_min (params, &min, NULL); snd_pcm_hw_params_get_periods_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); } #endif if (alsa->buffer_time != -1) { /* set the buffer time */ CHECK (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, &alsa->buffer_time, NULL), buffer_time); GST_DEBUG_OBJECT (alsa, "buffer time %u", alsa->buffer_time); } if (alsa->period_time != -1) { /* set the period time */ CHECK (snd_pcm_hw_params_set_period_time_near (alsa->handle, params, &alsa->period_time, NULL), period_time); GST_DEBUG_OBJECT (alsa, "period time %u", alsa->period_time); } /* write the parameters to device */ CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size), buffer_size); CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, NULL), period_size); snd_pcm_hw_params_free (params); return 0; /* ERRORS */ no_config: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Broken configuration for recording: no configurations available: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } wrong_access: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Access type not available for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_sample_format: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Sample format not available for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_channels: { gchar *msg = NULL; if ((alsa->channels) == 1) msg = g_strdup (_("Could not open device for recording in mono mode.")); if ((alsa->channels) == 2) msg = g_strdup (_("Could not open device for recording in stereo mode.")); if ((alsa->channels) > 2) msg = g_strdup_printf (_ ("Could not open device for recording in %d-channel mode"), alsa->channels); GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg), ("%s", snd_strerror (err))); g_free (msg); snd_pcm_hw_params_free (params); return err; } no_rate: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Rate %iHz not available for recording: %s", alsa->rate, snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } rate_match: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Rate doesn't match (requested %iHz, get %iHz)", alsa->rate, err)); snd_pcm_hw_params_free (params); return -EINVAL; } buffer_time: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set buffer time %i for recording: %s", alsa->buffer_time, snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } buffer_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get buffer size for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } period_time: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set period time %i for recording: %s", alsa->period_time, snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } period_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get period size for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } set_hw_params: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set hw params for recording: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } }
int main(int argc, char *argv[]) { const char *device_name = "hw"; snd_pcm_t *pcm; snd_pcm_hw_params_t *hw_params; unsigned int i; unsigned int min, max; int any_rate; int err; if (argc > 1) device_name = argv[1]; err = snd_pcm_open(&pcm, device_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if (err < 0) { fprintf(stderr, "cannot open device '%s': %s\n", device_name, snd_strerror(err)); return 1; } snd_pcm_hw_params_alloca(&hw_params); err = snd_pcm_hw_params_any(pcm, hw_params); if (err < 0) { fprintf(stderr, "cannot get hardware parameters: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } printf("Device: %s (type: %s)\n", device_name, snd_pcm_type_name(snd_pcm_type(pcm))); printf("Access types:"); for (i = 0; i < ARRAY_SIZE(accesses); ++i) { if (!snd_pcm_hw_params_test_access(pcm, hw_params, accesses[i])) printf(" %s", snd_pcm_access_name(accesses[i])); } putchar('\n'); printf("Formats:"); for (i = 0; i < ARRAY_SIZE(formats); ++i) { if (!snd_pcm_hw_params_test_format(pcm, hw_params, formats[i])) printf(" %s", snd_pcm_format_name(formats[i])); } putchar('\n'); err = snd_pcm_hw_params_get_channels_min(hw_params, &min); if (err < 0) { fprintf(stderr, "cannot get minimum channels count: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } err = snd_pcm_hw_params_get_channels_max(hw_params, &max); if (err < 0) { fprintf(stderr, "cannot get maximum channels count: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } printf("Channels:"); for (i = min; i <= max; ++i) { if (!snd_pcm_hw_params_test_channels(pcm, hw_params, i)) printf(" %u", i); } putchar('\n'); err = snd_pcm_hw_params_get_rate_min(hw_params, &min, NULL); if (err < 0) { fprintf(stderr, "cannot get minimum rate: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } err = snd_pcm_hw_params_get_rate_max(hw_params, &max, NULL); if (err < 0) { fprintf(stderr, "cannot get maximum rate: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } printf("Sample rates:"); if (min == max) printf(" %u", min); else if (!snd_pcm_hw_params_test_rate(pcm, hw_params, min + 1, 0)) printf(" %u-%u", min, max); else { any_rate = 0; for (i = 0; i < ARRAY_SIZE(rates); ++i) { if (!snd_pcm_hw_params_test_rate(pcm, hw_params, rates[i], 0)) { any_rate = 1; printf(" %u", rates[i]); } } if (!any_rate) printf(" %u-%u", min, max); } putchar('\n'); err = snd_pcm_hw_params_get_period_time_min(hw_params, &min, NULL); if (err < 0) { fprintf(stderr, "cannot get minimum period time: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } err = snd_pcm_hw_params_get_period_time_max(hw_params, &max, NULL); if (err < 0) { fprintf(stderr, "cannot get maximum period time: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } printf("Interrupt interval: %u-%u us\n", min, max); err = snd_pcm_hw_params_get_buffer_time_min(hw_params, &min, NULL); if (err < 0) { fprintf(stderr, "cannot get minimum buffer time: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &max, NULL); if (err < 0) { fprintf(stderr, "cannot get maximum buffer time: %s\n", snd_strerror(err)); snd_pcm_close(pcm); return 1; } printf("Buffer size: %u-%u us\n", min, max); snd_pcm_close(pcm); return 0; }
bool AlsaRenderer::SetupHwParams() { snd_pcm_hw_params_t* params; /* allocate a hardware parameters object */ snd_pcm_hw_params_malloc(¶ms); /* choose all parameters */ snd_pcm_hw_params_any(m_PcmHandle, params); /* enable hardware resampling */ snd_pcm_hw_params_set_rate_resample(m_PcmHandle, params, m_Resample); /* set the interleaved read/write format */ snd_pcm_hw_params_set_access(m_PcmHandle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(m_PcmHandle, params, SND_PCM_FORMAT_S16_LE); /* set the count of channels */ snd_pcm_hw_params_get_channels_max(params, &m_Channels.max); snd_pcm_hw_params_get_channels_min(params, &m_Channels.min); if (m_Channels.val < m_Channels.min || m_Channels.val > m_Channels.max) m_Channels.val = m_Channels.min; snd_pcm_hw_params_set_channels(m_PcmHandle, params, m_Channels.val); /* set the stream rate */ snd_pcm_hw_params_get_rate_max(params, &m_SampleRate.max, &m_Dir); snd_pcm_hw_params_get_rate_min(params, &m_SampleRate.min, &m_Dir); if (m_SampleRate.val < m_SampleRate.min || m_SampleRate.val > m_SampleRate.max) m_SampleRate.val = m_SampleRate.min; printf("sample rate max:%d, min:%d, val:%d\n", m_SampleRate.max, m_SampleRate.min, m_SampleRate.val); snd_pcm_hw_params_set_rate(m_PcmHandle, params, m_SampleRate.val, m_Dir); /* we can set period and buffer by size or time */ /* by default we use "size" (count of frames) */ /* set how many frames in a buffer (a buffer cantains several periods) */ snd_pcm_hw_params_get_buffer_size_max(params, &m_BufferSize.max); snd_pcm_hw_params_get_buffer_size_min(params, &m_BufferSize.min); /* detect period time and buffer time range */ snd_pcm_hw_params_get_buffer_time_max(params, &m_BufferTime.max, &m_Dir); snd_pcm_hw_params_get_buffer_time_min(params, &m_BufferTime.min, &m_Dir); m_BufferTime.val = std::max(m_BufferTime.max / 2, m_BufferTime.min); //m_BufferTime.val = m_BufferTime.min + (m_BufferTime.max - m_BufferTime.min) /2; printf("buffer time max:%d, min:%d, val:%d\n", m_BufferTime.max, m_BufferTime.min, m_BufferTime.val); //(m_BufferTime.max > 120000) ? 120000 : m_BufferTime.max;//120000 snd_pcm_hw_params_set_buffer_time_near(m_PcmHandle, params, &m_BufferTime.val, &m_Dir); snd_pcm_hw_params_get_period_time_max(params, &m_PeriodTime.max, &m_Dir); snd_pcm_hw_params_get_period_time_min(params, &m_PeriodTime.min, &m_Dir); m_PeriodTime.val = m_BufferTime.val / 4; //m_PeriodTime.val = m_PeriodTime.min + (m_PeriodTime.max - m_PeriodTime.min) / 2; printf("period time max:%d, min:%d, val:%d\n", m_PeriodTime.max, m_PeriodTime.min, m_PeriodTime.val); snd_pcm_hw_params_set_period_time_near(m_PcmHandle, params, &m_PeriodTime.val, &m_Dir); int ret = snd_pcm_hw_params(m_PcmHandle, params); if (ret != 0) { snd_pcm_hw_params_free(params); return false; } // get period size again snd_pcm_hw_params_get_period_size(params, &m_PeriodSize.val, &m_Dir); snd_pcm_hw_params_get_buffer_size(params, &m_BufferSize.val); m_BitsPerSample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); m_FrameLength = (m_BitsPerSample/8 * m_Channels.val); //mPeriodBufferLength = m_PeriodSize.val * m_FrameLength ; snd_pcm_hw_params_free(params); return true; }
int setup_pcmdev(char *pcm_name) { snd_pcm_hw_params_t *params; snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; int rate = 44100, dir; snd_pcm_uframes_t persize, persize2; int maxrate, minrate; unsigned int pertime, perTmin, perTmax; snd_pcm_uframes_t bufsize, perSmin, perSmax, bufSmin, bufSmax; /* Allocate the snd_pcm_hw_params_t structure on the stack. */ snd_pcm_hw_params_alloca(¶ms); /* Open PCM device for playback. */ if (snd_pcm_open(&handle, pcm_name, stream, 0) < 0) { fprintf(stderr, "Error opening PCM device %s\n", pcm_name); return(-1); } /* Init params with full configuration space */ if (snd_pcm_hw_params_any(handle, params) < 0) { fprintf(stderr, "Can not configure this PCM device.\n"); return(-1); } /* set interleaved mode */ if (snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { fprintf(stderr, "Error setting access.\n"); return(-1); } /* Set sample format */ if (snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE) < 0) { fprintf(stderr, "Error setting format.\n"); return(-1); } /* Set sample rate.*/ if (snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0) < 0) { fprintf(stderr, "Error setting rate.\n"); return(-1); } /* Set number of channels */ if (snd_pcm_hw_params_set_channels(handle, params, nchan) < 0) { fprintf(stderr, "Error setting channels.\n"); return(-1); } /* Set period size to n frames (samples). */ persize = 1024; dir=0; if (snd_pcm_hw_params_set_period_size_near(handle,params, &persize, &dir)< 0) { fprintf(stderr, "Error setting period size to %d.\n", (int) persize); return(-1); } /* Apply HW parameter settings to PCM device */ if (snd_pcm_hw_params(handle, params) < 0) { fprintf(stderr, "Error setting HW params.\n"); return(-1); } /*get some inof about the hardware*/ // printf("\n ---------- hardware parameters ------------ \n"); snd_pcm_hw_params_get_rate_min (params, &minrate, &dir); //printf("min rate: %d samples per sec\n",minrate); snd_pcm_hw_params_get_rate_max (params, &maxrate, &dir); //printf("max rate: %d samples per sec\n",maxrate); snd_pcm_hw_params_get_period_time (params, &pertime, &dir); //printf("period: %d microseconds\n",pertime); snd_pcm_hw_params_get_period_time_min (params, &perTmin, &dir); snd_pcm_hw_params_get_period_time_min (params, &perTmax, &dir); //printf("min period time: %d microseconds\n",perTmin); //printf("max period time: %d microseconds\n",perTmax); snd_pcm_hw_params_get_period_size (params, &persize2, &dir); //printf("period: %d frames\n",(int) persize2); snd_pcm_hw_params_get_period_size_min (params, &perSmin, &dir); snd_pcm_hw_params_get_period_size_min (params, &perSmax, &dir); //printf("min period size: %d frames\n",(int) perSmin); //printf("max period size: %d frames\n",(int) perSmax); snd_pcm_hw_params_get_buffer_size (params, &bufsize); //printf("buffer size: %d frames\n",(int) bufsize); snd_pcm_hw_params_get_buffer_size_min (params, &bufSmin); snd_pcm_hw_params_get_buffer_size_min (params, &bufSmax); //printf("min buffer size: %d frames\n",(int) bufSmin); //printf("max buffer size: %d frames\n",(int) bufSmax); return (double) persize2; }
void info(char *dev_name, snd_pcm_stream_t stream) { snd_pcm_hw_params_t *hw_params; int err; snd_pcm_t *handle; unsigned int max; unsigned int min; unsigned int val; unsigned int dir; snd_pcm_uframes_t frames; if ((err = snd_pcm_open (&handle, dev_name, stream, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", dev_name, snd_strerror (err)); return; } if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_get_channels_max(hw_params, &max)) < 0) { fprintf (stderr, "cannot (%s)\n", snd_strerror (err)); exit (1); } printf("max channels %d\n", max); if ((err = snd_pcm_hw_params_get_channels_min(hw_params, &min)) < 0) { fprintf (stderr, "cannot get channel info (%s)\n", snd_strerror (err)); exit (1); } printf("min channels %d\n", min); /* if ((err = snd_pcm_hw_params_get_sbits(hw_params)) < 0) { fprintf (stderr, "cannot get bits info (%s)\n", snd_strerror (err)); exit (1); } printf("bits %d\n", err); */ if ((err = snd_pcm_hw_params_get_rate_min(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min rate (%s)\n", snd_strerror (err)); exit (1); } printf("min rate %d hz\n", val); if ((err = snd_pcm_hw_params_get_rate_max(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get max rate (%s)\n", snd_strerror (err)); exit (1); } printf("max rate %d hz\n", val); if ((err = snd_pcm_hw_params_get_period_time_min(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min period time (%s)\n", snd_strerror (err)); exit (1); } printf("min period time %d usecs\n", val); if ((err = snd_pcm_hw_params_get_period_time_max(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get max period time (%s)\n", snd_strerror (err)); exit (1); } printf("max period time %d usecs\n", val); if ((err = snd_pcm_hw_params_get_period_size_min(hw_params, &frames, &dir)) < 0) { fprintf (stderr, "cannot get min period size (%s)\n", snd_strerror (err)); exit (1); } printf("min period size in frames %d\n", frames); if ((err = snd_pcm_hw_params_get_period_size_max(hw_params, &frames, &dir)) < 0) { fprintf (stderr, "cannot get max period size (%s)\n", snd_strerror (err)); exit (1); } printf("max period size in frames %d\n", frames); if ((err = snd_pcm_hw_params_get_periods_min(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min periods (%s)\n", snd_strerror (err)); exit (1); } printf("min periods per buffer %d\n", val); if ((err = snd_pcm_hw_params_get_periods_max(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min periods (%s)\n", snd_strerror (err)); exit (1); } printf("max periods per buffer %d\n", val); if ((err = snd_pcm_hw_params_get_buffer_time_min(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get min buffer time (%s)\n", snd_strerror (err)); exit (1); } printf("min buffer time %d usecs\n", val); if ((err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &val, &dir)) < 0) { fprintf (stderr, "cannot get max buffer time (%s)\n", snd_strerror (err)); exit (1); } printf("max buffer time %d usecs\n", val); if ((err = snd_pcm_hw_params_get_buffer_size_min(hw_params, &frames)) < 0) { fprintf (stderr, "cannot get min buffer size (%s)\n", snd_strerror (err)); exit (1); } printf("min buffer size in frames %d\n", frames); if ((err = snd_pcm_hw_params_get_buffer_size_max(hw_params, &frames)) < 0) { fprintf (stderr, "cannot get max buffer size (%s)\n", snd_strerror (err)); exit (1); } printf("max buffer size in frames %d\n", frames); }
/** * Set up the snd_pcm_t object which was opened by the caller. Set up * the configured settings and the audio format. */ static bool alsa_setup(struct alsa_data *ad, struct audio_format *audio_format, GError **error) { snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; unsigned int sample_rate = audio_format->sample_rate; unsigned int channels = audio_format->channels; snd_pcm_uframes_t alsa_buffer_size; snd_pcm_uframes_t alsa_period_size; int err; const char *cmd = NULL; int retry = MPD_ALSA_RETRY_NR; unsigned int period_time, period_time_ro; unsigned int buffer_time; period_time_ro = period_time = ad->period_time; configure_hw: /* configure HW params */ snd_pcm_hw_params_alloca(&hwparams); cmd = "snd_pcm_hw_params_any"; err = snd_pcm_hw_params_any(ad->pcm, hwparams); if (err < 0) goto error; if (ad->use_mmap) { err = snd_pcm_hw_params_set_access(ad->pcm, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED); if (err < 0) { g_warning("Cannot set mmap'ed mode on ALSA device \"%s\": %s\n", alsa_device(ad), snd_strerror(-err)); g_warning("Falling back to direct write mode\n"); ad->use_mmap = false; } else ad->writei = snd_pcm_mmap_writei; } if (!ad->use_mmap) { cmd = "snd_pcm_hw_params_set_access"; err = snd_pcm_hw_params_set_access(ad->pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) goto error; ad->writei = snd_pcm_writei; } err = alsa_output_setup_format(ad->pcm, hwparams, audio_format); if (err < 0) { g_set_error(error, alsa_output_quark(), err, "ALSA device \"%s\" does not support format %s: %s", alsa_device(ad), sample_format_to_string(audio_format->format), snd_strerror(-err)); return false; } err = snd_pcm_hw_params_set_channels_near(ad->pcm, hwparams, &channels); if (err < 0) { g_set_error(error, alsa_output_quark(), err, "ALSA device \"%s\" does not support %i channels: %s", alsa_device(ad), (int)audio_format->channels, snd_strerror(-err)); return false; } audio_format->channels = (int8_t)channels; err = snd_pcm_hw_params_set_rate_near(ad->pcm, hwparams, &sample_rate, NULL); if (err < 0 || sample_rate == 0) { g_set_error(error, alsa_output_quark(), err, "ALSA device \"%s\" does not support %u Hz audio", alsa_device(ad), audio_format->sample_rate); return false; } audio_format->sample_rate = sample_rate; snd_pcm_uframes_t buffer_size_min, buffer_size_max; snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min); snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size_max); unsigned buffer_time_min, buffer_time_max; snd_pcm_hw_params_get_buffer_time_min(hwparams, &buffer_time_min, 0); snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time_max, 0); g_debug("buffer: size=%u..%u time=%u..%u", (unsigned)buffer_size_min, (unsigned)buffer_size_max, buffer_time_min, buffer_time_max); snd_pcm_uframes_t period_size_min, period_size_max; snd_pcm_hw_params_get_period_size_min(hwparams, &period_size_min, 0); snd_pcm_hw_params_get_period_size_max(hwparams, &period_size_max, 0); unsigned period_time_min, period_time_max; snd_pcm_hw_params_get_period_time_min(hwparams, &period_time_min, 0); snd_pcm_hw_params_get_period_time_max(hwparams, &period_time_max, 0); g_debug("period: size=%u..%u time=%u..%u", (unsigned)period_size_min, (unsigned)period_size_max, period_time_min, period_time_max); if (ad->buffer_time > 0) { buffer_time = ad->buffer_time; cmd = "snd_pcm_hw_params_set_buffer_time_near"; err = snd_pcm_hw_params_set_buffer_time_near(ad->pcm, hwparams, &buffer_time, NULL); if (err < 0) goto error; } else { err = snd_pcm_hw_params_get_buffer_time(hwparams, &buffer_time, NULL); if (err < 0) buffer_time = 0; } if (period_time_ro == 0 && buffer_time >= 10000) { period_time_ro = period_time = buffer_time / 4; g_debug("default period_time = buffer_time/4 = %u/4 = %u", buffer_time, period_time); } if (period_time_ro > 0) { period_time = period_time_ro; cmd = "snd_pcm_hw_params_set_period_time_near"; err = snd_pcm_hw_params_set_period_time_near(ad->pcm, hwparams, &period_time, NULL); if (err < 0) goto error; } cmd = "snd_pcm_hw_params"; err = snd_pcm_hw_params(ad->pcm, hwparams); if (err == -EPIPE && --retry > 0 && period_time_ro > 0) { period_time_ro = period_time_ro >> 1; goto configure_hw; } else if (err < 0)