static void *alsa_init(const char *device, unsigned rate, unsigned latency) { alsa_t *alsa = (alsa_t*)calloc(1, sizeof(alsa_t)); if (!alsa) return NULL; snd_pcm_hw_params_t *params = NULL; snd_pcm_sw_params_t *sw_params = NULL; unsigned latency_usec = latency * 1000; unsigned channels = 2; unsigned periods = 4; snd_pcm_format_t format; const char *alsa_dev = "default"; if (device) alsa_dev = device; snd_pcm_uframes_t buffer_size; TRY_ALSA(snd_pcm_open(&alsa->pcm, alsa_dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)); TRY_ALSA(snd_pcm_hw_params_malloc(¶ms)); alsa->has_float = 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)); snd_pcm_hw_params_get_period_size(params, &buffer_size, NULL); RARCH_LOG("ALSA: Period size: %d frames\n", (int)buffer_size); snd_pcm_hw_params_get_buffer_size(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->can_pause = snd_pcm_hw_params_can_pause(params); RARCH_LOG("ALSA: Can pause: %s.\n", alsa->can_pause ? "yes" : "no"); 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); 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); if (alsa) { if (alsa->pcm) snd_pcm_close(alsa->pcm); free(alsa); } return NULL; }
static void alsa_configure (struct sound_device *sd) { int val, err, dir; unsigned uval; struct alsa_params *p = (struct alsa_params *) sd->data; snd_pcm_uframes_t buffer_size; xassert (p->handle != 0); err = snd_pcm_hw_params_malloc (&p->hwparams); if (err < 0) alsa_sound_perror ("Could not allocate hardware parameter structure", err); err = snd_pcm_sw_params_malloc (&p->swparams); if (err < 0) alsa_sound_perror ("Could not allocate software parameter structure", err); err = snd_pcm_hw_params_any (p->handle, p->hwparams); if (err < 0) alsa_sound_perror ("Could not initialize hardware parameter structure", err); err = snd_pcm_hw_params_set_access (p->handle, p->hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) alsa_sound_perror ("Could not set access type", err); val = sd->format; err = snd_pcm_hw_params_set_format (p->handle, p->hwparams, val); if (err < 0) alsa_sound_perror ("Could not set sound format", err); uval = sd->sample_rate; err = snd_pcm_hw_params_set_rate_near (p->handle, p->hwparams, &uval, 0); if (err < 0) alsa_sound_perror ("Could not set sample rate", err); val = sd->channels; err = snd_pcm_hw_params_set_channels (p->handle, p->hwparams, val); if (err < 0) alsa_sound_perror ("Could not set channel count", err); err = snd_pcm_hw_params (p->handle, p->hwparams); if (err < 0) alsa_sound_perror ("Could not set parameters", err); err = snd_pcm_hw_params_get_period_size (p->hwparams, &p->period_size, &dir); if (err < 0) alsa_sound_perror ("Unable to get period size for playback", err); err = snd_pcm_hw_params_get_buffer_size (p->hwparams, &buffer_size); if (err < 0) alsa_sound_perror ("Unable to get buffer size for playback", err); err = snd_pcm_sw_params_current (p->handle, p->swparams); if (err < 0) alsa_sound_perror ("Unable to determine current swparams for playback", err); /* Start the transfer when the buffer is almost full */ err = snd_pcm_sw_params_set_start_threshold (p->handle, p->swparams, (buffer_size / p->period_size) * p->period_size); if (err < 0) alsa_sound_perror ("Unable to set start threshold mode for playback", err); /* Allow the transfer when at least period_size samples can be processed */ err = snd_pcm_sw_params_set_avail_min (p->handle, p->swparams, p->period_size); if (err < 0) alsa_sound_perror ("Unable to set avail min for playback", err); err = snd_pcm_sw_params (p->handle, p->swparams); if (err < 0) alsa_sound_perror ("Unable to set sw params for playback\n", err); snd_pcm_hw_params_free (p->hwparams); p->hwparams = NULL; snd_pcm_sw_params_free (p->swparams); p->swparams = NULL; err = snd_pcm_prepare (p->handle); if (err < 0) alsa_sound_perror ("Could not prepare audio interface for use", err); if (sd->volume > 0) { int chn; snd_mixer_t *handle; snd_mixer_elem_t *e; const char *file = sd->file ? sd->file : DEFAULT_ALSA_SOUND_DEVICE; if (snd_mixer_open (&handle, 0) >= 0) { if (snd_mixer_attach (handle, file) >= 0 && snd_mixer_load (handle) >= 0 && snd_mixer_selem_register (handle, NULL, NULL) >= 0) for (e = snd_mixer_first_elem (handle); e; e = snd_mixer_elem_next (e)) { if (snd_mixer_selem_has_playback_volume (e)) { long pmin, pmax, vol; snd_mixer_selem_get_playback_volume_range (e, &pmin, &pmax); vol = pmin + (sd->volume * (pmax - pmin)) / 100; for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) snd_mixer_selem_set_playback_volume (e, chn, vol); } } snd_mixer_close (handle); } } }
Error AudioDriverALSA::init() { active=false; thread_exited=false; exit_thread=false; pcm_open = false; samples_in = NULL; samples_out = NULL; mix_rate = GLOBAL_DEF("audio/mix_rate",44100); output_format = OUTPUT_STEREO; channels = 2; int status; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; #define CHECK_FAIL(m_cond)\ if (m_cond) {\ fprintf(stderr,"ALSA ERR: %s\n",snd_strerror(status));\ snd_pcm_close(pcm_handle);\ ERR_FAIL_COND_V(m_cond,ERR_CANT_OPEN);\ } //todo, add //6 chans - "plug:surround51" //4 chans - "plug:surround40"; status = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); ERR_FAIL_COND_V( status<0, ERR_CANT_OPEN ); snd_pcm_hw_params_alloca(&hwparams); status = snd_pcm_hw_params_any(pcm_handle, hwparams); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); CHECK_FAIL( status<0 ); //not interested in anything else status = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE); CHECK_FAIL( status<0 ); //todo: support 4 and 6 status = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &mix_rate, NULL); CHECK_FAIL( status<0 ); int latency = GLOBAL_DEF("audio/output_latency",25); buffer_size = nearest_power_of_2( latency * mix_rate / 1000 ); // set buffer size from project settings status = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size); CHECK_FAIL( status<0 ); // make period size 1/8 period_size = buffer_size >> 3; status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, NULL); CHECK_FAIL( status<0 ); unsigned int periods=2; status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL); CHECK_FAIL( status<0 ); status = snd_pcm_hw_params(pcm_handle,hwparams); CHECK_FAIL( status<0 ); //snd_pcm_hw_params_free(&hwparams); snd_pcm_sw_params_alloca(&swparams); status = snd_pcm_sw_params_current(pcm_handle, swparams); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, period_size); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1); CHECK_FAIL( status<0 ); status = snd_pcm_sw_params(pcm_handle, swparams); CHECK_FAIL( status<0 ); samples_in = memnew_arr(int32_t, period_size*channels); samples_out = memnew_arr(int16_t, period_size*channels); snd_pcm_nonblock(pcm_handle, 0); mutex=Mutex::create(); thread = Thread::create(AudioDriverALSA::thread_func, this); return OK; };
/* setup alsa data transfer behavior */ static inline int alsa_set_swparams(ao_device *device) { ao_alsa_internal *internal = (ao_alsa_internal *) device->internal; snd_pcm_sw_params_t *params; snd_pcm_uframes_t boundary; int err; /* allocate the software parameter structure */ snd_pcm_sw_params_alloca(¶ms); /* fetch the current software parameters */ err = snd_pcm_sw_params_current(internal->pcm_handle, params); if (err < 0){ adebug("snd_pcm_sw_params_current() failed.\n"); return err; } #if 0 /* the below causes more trouble than it cures */ /* allow transfers to start when there is one period */ err = snd_pcm_sw_params_set_start_threshold(internal->pcm_handle, params, internal->period_size); if (err < 0){ adebug("snd_pcm_sw_params_set_start_threshold() failed.\n"); //return err; } /* require a minimum of one full transfer in the buffer */ err = snd_pcm_sw_params_set_avail_min(internal->pcm_handle, params, internal->period_size); if (err < 0){ adebug("snd_pcm_sw_params_set_avail_min() failed.\n"); //return err; } #endif /* do not align transfers; this is obsolete/deprecated in ALSA 1.x where the transfer alignemnt is always 1 (except for buggy drivers like VIA 82xx which still demand aligned transfers regardless of setting, in violation of the ALSA API docs) */ err = snd_pcm_sw_params_set_xfer_align(internal->pcm_handle, params, 1); if (err < 0){ adebug("snd_pcm_sw_params_set_xfer_align() failed.\n"); //return err; } /* get the boundary size */ err = snd_pcm_sw_params_get_boundary(params,&boundary); if (err < 0){ adebug("snd_pcm_sw_params_get_boundary() failed.\n"); }else{ /* force a work-ahead silence buffer; this is a fix, again for VIA 82xx, where non-MMIO transfers will buffer into period-size transfers, but the last transfer is usually undersized and playback falls off the end of the submitted data. */ err = snd_pcm_sw_params_set_silence_size(internal->pcm_handle, params, boundary); if (err < 0){ adebug("snd_pcm_sw_params_set_silence_size() failed.\n"); //return err; } } /* commit the params structure to ALSA */ err = snd_pcm_sw_params(internal->pcm_handle, params); if (err < 0){ adebug("snd_pcm_sw_params() failed.\n"); return err; } return 1; }
/*---------------------------------------------------------------------- | AlsaOutput_Configure +---------------------------------------------------------------------*/ static BLT_Result AlsaOutput_Configure(AlsaOutput* self, const BLT_PcmMediaType* format) { snd_pcm_hw_params_t* hw_params; snd_pcm_sw_params_t* sw_params; unsigned int rate = format->sample_rate; unsigned int buffer_time = BLT_ALSA_DEFAULT_BUFFER_TIME; snd_pcm_uframes_t buffer_size = 0; snd_pcm_uframes_t period_size = BLT_ALSA_DEFAULT_PERIOD_SIZE; snd_pcm_format_t pcm_format_id = SND_PCM_FORMAT_UNKNOWN; int ior; BLT_Result result; switch (self->state) { case BLT_ALSA_OUTPUT_STATE_CLOSED: /* first, we need to open the device */ result = AlsaOutput_Open(self); if (BLT_FAILED(result)) return result; /* FALLTHROUGH */ case BLT_ALSA_OUTPUT_STATE_CONFIGURED: case BLT_ALSA_OUTPUT_STATE_PREPARED: /* check to see if the format has changed */ if (format->sample_rate != self->media_type.sample_rate || format->channel_count != self->media_type.channel_count || format->bits_per_sample != self->media_type.bits_per_sample) { /* new format */ /* check the format */ if (format->sample_rate == 0 || format->channel_count == 0 || format->bits_per_sample == 0) { return BLT_ERROR_INVALID_MEDIA_FORMAT; } /* unprepare (forget current settings) */ result = AlsaOutput_Unprepare(self); if (BLT_FAILED(result)) return result; } else { /* same format, do nothing */ return BLT_SUCCESS; } /* FALLTHROUGH */ case BLT_ALSA_OUTPUT_STATE_OPEN: /* configure the device with the new format */ ATX_LOG_FINER("configuring ALSA device"); /* copy the format */ self->media_type = *format; ATX_LOG_FINE_3("new format: sr=%d, ch=%d, bps=%d", format->sample_rate, format->channel_count, format->bits_per_sample); /* allocate a new blank configuration */ snd_pcm_hw_params_alloca_no_assert(&hw_params); snd_pcm_hw_params_any(self->device_handle, hw_params); /* use interleaved access */ ior = snd_pcm_hw_params_set_access(self->device_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (ior != 0) { ATX_LOG_WARNING_2("snd_pcm_hw_params_set_access failed (%d:%s)", ior, snd_strerror(ior)); return BLT_FAILURE; } /* set the sample rate */ ior = snd_pcm_hw_params_set_rate_near(self->device_handle, hw_params, &rate, NULL); if (ior != 0) { ATX_LOG_WARNING_3("snd_pcm_hw_params_set_rate_near(%d) failed (%d:%s)", rate, ior, snd_strerror(ior)); return BLT_FAILURE; } /* set the number of channels */ ior = snd_pcm_hw_params_set_channels(self->device_handle, hw_params, format->channel_count); if (ior != 0) { ATX_LOG_WARNING_3("snd_pcm_hw_params_set_channels(%d) failed (%d:%s)", format->channel_count, ior, snd_strerror(ior)); return BLT_FAILURE; } /* set the sample format */ switch (format->sample_format) { case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_LE: ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_LE"); switch (format->bits_per_sample) { case 8: pcm_format_id = SND_PCM_FORMAT_S8; break; case 16: pcm_format_id = SND_PCM_FORMAT_S16_LE; break; case 24: pcm_format_id = SND_PCM_FORMAT_S24_3LE; break; case 32: pcm_format_id = SND_PCM_FORMAT_S32_LE; break; } break; case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_LE: ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_LE"); switch (format->bits_per_sample) { case 8: pcm_format_id = SND_PCM_FORMAT_U8; break; case 16: pcm_format_id = SND_PCM_FORMAT_U16_LE; break; case 24: pcm_format_id = SND_PCM_FORMAT_U24_3LE; break; case 32: pcm_format_id = SND_PCM_FORMAT_U32_LE; break; } break; case BLT_PCM_SAMPLE_FORMAT_FLOAT_LE: ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_FLOAT_LE"); switch (format->bits_per_sample) { case 32: pcm_format_id = SND_PCM_FORMAT_FLOAT_LE; break; } break; case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_BE: ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_BE"); switch (format->bits_per_sample) { case 8: pcm_format_id = SND_PCM_FORMAT_S8; break; case 16: pcm_format_id = SND_PCM_FORMAT_S16_BE; break; case 24: pcm_format_id = SND_PCM_FORMAT_S24_3BE; break; case 32: pcm_format_id = SND_PCM_FORMAT_S32_BE; break; } break; case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_BE: ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_BE"); switch (format->bits_per_sample) { case 8: pcm_format_id = SND_PCM_FORMAT_U8; break; case 16: pcm_format_id = SND_PCM_FORMAT_U16_BE; break; case 24: pcm_format_id = SND_PCM_FORMAT_U24_3BE; break; case 32: pcm_format_id = SND_PCM_FORMAT_U32_BE; break; } break; case BLT_PCM_SAMPLE_FORMAT_FLOAT_BE: ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_FLOAT_LE"); switch (format->bits_per_sample) { case 32: pcm_format_id = SND_PCM_FORMAT_FLOAT_BE; break; } break; } if (pcm_format_id == SND_PCM_FORMAT_UNKNOWN) { return BLT_ERROR_INVALID_MEDIA_TYPE; } ior = snd_pcm_hw_params_set_format(self->device_handle, hw_params, pcm_format_id); if (ior != 0) { ATX_LOG_WARNING_2("snd_pcm_hw_params_set_format() failed (%d:%s)", ior, snd_strerror(ior)); return BLT_FAILURE; } /* set the period size */ ior = snd_pcm_hw_params_set_period_size_near(self->device_handle, hw_params, &period_size, NULL); if (ior != 0) { ATX_LOG_WARNING_2("snd_pcm_hw_params_set_period_size_near() failed (%d:%s)", ior, snd_strerror(ior)); return BLT_FAILURE; } /* set the buffer time (duration) */ ior = snd_pcm_hw_params_set_buffer_time_near(self->device_handle, hw_params, &buffer_time, NULL); if (ior != 0) { ATX_LOG_WARNING_2("snd_pcm_hw_params_set_buffer_time_near() failed (%d:%s)", ior, snd_strerror(ior)); return BLT_FAILURE; } /* get the actual buffer size */ snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size); /* activate this configuration */ ior = snd_pcm_hw_params(self->device_handle, hw_params); if (ior != 0) { ATX_LOG_WARNING_2("snd_pcm_hw_params() failed (%d:%s)", ior, snd_strerror(ior)); return BLT_FAILURE; } /* configure the software parameters */ snd_pcm_sw_params_alloca_no_assert(&sw_params); snd_pcm_sw_params_current(self->device_handle, sw_params); /* set the start threshold to 1/2 the buffer size */ snd_pcm_sw_params_set_start_threshold(self->device_handle, sw_params, buffer_size/2); /* set the buffer alignment */ /* NOTE: this call is now obsolete */ /* snd_pcm_sw_params_set_xfer_align(self->device_handle, sw_params, 1); */ /* activate the sofware parameters */ ior = snd_pcm_sw_params(self->device_handle, sw_params); if (ior != 0) { ATX_LOG_SEVERE_2("snd_pcm_sw_params() failed (%d:%s)", ior, snd_strerror(ior)); return BLT_FAILURE; } /* print status info */ { snd_pcm_uframes_t val; ATX_LOG_FINER_1("sample type = %x", pcm_format_id); if (rate != format->sample_rate) { ATX_LOG_FINER_1("actual sample = %d", rate); } ATX_LOG_FINER_1("actual buffer time = %d", (int)buffer_time); ATX_LOG_FINER_1("buffer size = %d", (int)buffer_size); snd_pcm_sw_params_get_start_threshold(sw_params, &val); ATX_LOG_FINER_1("start threshold = %d", (int)val); snd_pcm_sw_params_get_stop_threshold(sw_params, &val); ATX_LOG_FINER_1("stop threshold = %d", (int)val); snd_pcm_hw_params_get_period_size(hw_params, &val, NULL); ATX_LOG_FINER_1("period size = %d", (int)val); } break; } /* update the state */ AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED); return BLT_SUCCESS; }
static int set_swparams (GstAlsaSrc * alsa) { int err; snd_pcm_sw_params_t *params; snd_pcm_sw_params_malloc (¶ms); /* get the current swparams */ CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config); /* allow the transfer when at least period_size samples can be processed */ CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params, alsa->period_size), set_avail); /* start the transfer on first read */ CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params, 0), start_threshold); /* use monotonic timestamping */ CHECK (snd_pcm_sw_params_set_tstamp_mode (alsa->handle, params, SND_PCM_TSTAMP_MMAP), tstamp_mode); #if GST_CHECK_ALSA_VERSION(1,0,16) /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */ #else /* align all transfers to 1 sample */ CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align); #endif /* write the parameters to the recording device */ CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params); snd_pcm_sw_params_free (params); return 0; /* ERRORS */ no_config: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to determine current swparams for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } start_threshold: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set start threshold mode for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } set_avail: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set avail min for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } tstamp_mode: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set tstamp mode for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } #if !GST_CHECK_ALSA_VERSION(1,0,16) set_align: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set transfer align for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } #endif set_sw_params: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set sw params for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } }
bool QAudioInputPrivate::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 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::AudioInput); 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_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.channels() ); 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, &freakuency, 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 if(audioBuffer == 0) audioBuffer = new char[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; }
Player::Player() { // printf("Player::Player()\n"); int rc=0; unsigned int val=0; int dir=0; /* Open PCM device for playback. */ rc = snd_pcm_open(&(this->m_pHandle), "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { printf("unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(&(this->m_pParams)); /* Fill it in with default values. */ rc = snd_pcm_hw_params_any(this->m_pHandle, this->m_pParams); if (rc < 0) { printf("Can not configure this PCM device: %s\n", snd_strerror(rc)); exit(1); } /* Set the desired hardware parameters. */ /* Interleaved mode */ rc = snd_pcm_hw_params_set_access(this->m_pHandle, this->m_pParams, SND_PCM_ACCESS_RW_INTERLEAVED); if (rc < 0) { printf("Failed to set PCM device to interleaved: %s\n", snd_strerror(rc)); exit(1); } /* Signed 16-bit little-endian format */ rc = snd_pcm_hw_params_set_format(this->m_pHandle, this->m_pParams, SND_PCM_FORMAT_S16_LE); if (rc < 0) { printf("Failed to set PCM device to 16-bit signed PCM: %s\n", snd_strerror(rc)); exit(1); } /* Two channels (mono) */ rc = snd_pcm_hw_params_set_channels(this->m_pHandle, this->m_pParams,channels); if (rc < 0) { printf("Failed to set PCM device to mono: %s\n", snd_strerror(rc)); exit(1); } /* 44100 bits/second sampling rate (CD quality) */ val = rate; rc = snd_pcm_hw_params_set_rate_near(this->m_pHandle, this->m_pParams, &val, 0); if (rc < 0) { printf("Failed to set PCM device to sample rate =%d: %s\n", rate,snd_strerror(rc)); exit(1); } if(val != rate){ printf("Rate doesn't match (request %iHz, get %iHz\n",rate,val); exit(1); } rc = snd_pcm_hw_params_set_buffer_time_near(this->m_pHandle, this->m_pParams, &buffer_time, &dir); if (rc < 0) { fprintf(stderr, "Failed to set PCM device to buffer time=%d: %s\n", val,snd_strerror(rc)); exit(1); } rc = snd_pcm_hw_params_set_period_time_near(this->m_pHandle, this->m_pParams, &period_time, &dir); if (rc < 0) { fprintf(stderr, "Failed to set PCM device to period time=%d: %s\n", val,snd_strerror(rc)); exit(1); } //chunk size rc = snd_pcm_hw_params_get_period_size(this->m_pParams, &period_size, &dir); if(rc < 0){ fprintf(stderr, "Failed to get period size for capture: %s\n", snd_strerror(rc)); exit(1); } this->m_frames = period_size; rc = snd_pcm_hw_params_get_buffer_size(this->m_pParams, &buffer_size); if(rc < 0){ fprintf(stderr, "Failed to get buffer size for capture: %s\n", snd_strerror(rc)); exit(1); } #ifdef DEBUG printf("Recorder alsa driver hw params setting\n"); printf("period size =%d frames\n", (int)period_size); printf("buffer size =%d frames\n", (int)buffer_size); snd_pcm_hw_params_get_period_time(this->m_pParams,&val, &dir); printf("period time =%d us\n",val); snd_pcm_hw_params_get_buffer_time(this->m_pParams,&val, &dir); printf("buffer time =%d us\n", val); snd_pcm_hw_params_get_periods(this->m_pParams, &val, &dir); printf("period per buffer =%d frames\n", val); #endif /* Write the parameters to the driver */ rc = snd_pcm_hw_params(this->m_pHandle, this->m_pParams); if (rc < 0) { printf("unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } #ifdef ALSA_OPT snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(&swparams); /* get the current swparams */ rc = snd_pcm_sw_params_current(this->m_pHandle, swparams); if (rc < 0) { printf("Unable to determine current swparams for playback: %s\n", snd_strerror(rc)); exit(1); } /* start the transfer when the buffer is almost full: */ /* (buffer_size / avail_min) * avail_min */ rc = snd_pcm_sw_params_set_start_threshold(this->m_pHandle, swparams, (buffer_size / period_size) * period_size); if (rc < 0) { printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(rc)); exit(1); } rc = snd_pcm_sw_params_set_avail_min(this->m_pHandle, swparams, period_size); if (rc < 0) { printf("Unable to set avail min for playback: %s\n", snd_strerror(rc)); exit(1); } /* write the parameters to the playback device */ rc = snd_pcm_sw_params(this->m_pHandle, swparams); if (rc < 0) { printf("Unable to set sw params for playback: %s\n", snd_strerror(rc)); exit(1); } #endif }
static snd_pcm_uframes_t set_params(snd_pcm_t *handle, snd_pcm_stream_t stream) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t chunk_size = 0; snd_pcm_uframes_t start_threshold; unsigned period_time = 0; unsigned buffer_time = 0; size_t chunk_bytes = 0; int err; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, params); if (err < 0) { printf("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) { printf("Access type not available"); exit(EXIT_FAILURE); } printf("format = %s, channels = %d, rate = %d\n", snd_pcm_format_name(hwparams.format),hwparams.channels,hwparams.rate); //err = snd_pcm_hw_params_set_format(handle, params, hwparams.format); err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); if (err < 0) { printf("Sample format non available"); exit(EXIT_FAILURE); } //err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); err = snd_pcm_hw_params_set_channels(handle, params, 2); if (err < 0) { printf("Channels count non available"); exit(EXIT_FAILURE); } #if 0 //add by yjc 2012/08/21 err = set_audio_clk_freq(hwparams.rate); if (err < 0){ printf("set_audio_clk_freq fail..........\n"); exit(EXIT_FAILURE); } #endif err = snd_pcm_hw_params_set_rate(handle, params, hwparams.rate, 0); if (err < 0) { printf("Rate non available"); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0); assert(err >= 0); if (buffer_time > 500000) buffer_time = 500000; period_time = buffer_time / 4; err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0); assert(err >= 0); err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); assert(err >= 0); err = snd_pcm_hw_params(handle, params); if (err < 0) { printf("Unable to install hw params:"); 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) { printf("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_set_avail_min(handle, swparams, chunk_size); if(stream == SND_PCM_STREAM_PLAYBACK) start_threshold = (buffer_size / chunk_size) * chunk_size; else start_threshold = 1; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err >= 0); err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, buffer_size); assert(err >= 0); if (snd_pcm_sw_params(handle, swparams) < 0) { printf("unable to install sw params:"); exit(EXIT_FAILURE); } //bits_per_sample = snd_pcm_format_physical_width(hwparams.format); bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); //bits_per_frame = bits_per_sample * hwparams.channels; bits_per_frame = bits_per_sample * 2; chunk_bytes = chunk_size * bits_per_frame / 8; printf("chunk_size = %d,chunk_bytes = %d,buffer_size = %d\n\n", (int)chunk_size,chunk_bytes,(int)buffer_size); return chunk_size; }
int sound_lowlevel_init( const char *device, int *freqptr, int *stereoptr ) { unsigned int exact_rate, periods; unsigned int val, n; snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; snd_pcm_uframes_t avail_min = 0, sound_periodsize, bsize = 0; static int first_init = 1; static int init_running = 0; const char *option; char tmp; int err, dir, nperiods = NUM_FRAMES; float hz; if( init_running ) return 0; init_running = 1; /* select a default device if we weren't explicitly given one */ option = device; while( option && *option ) { tmp = '*'; if( ( err = sscanf( option, " buffer=%i %n%c", &val, &n, &tmp ) > 0 ) && ( tmp == ',' || strlen( option ) == n ) ) { if( val < 1 ) { fprintf( stderr, "Bad value for ALSA buffer size %i, using default\n", val ); } else { bsize = val; } } else if( ( err = sscanf( option, " frames=%i %n%c", &val, &n, &tmp ) > 0 ) && ( tmp == ',' || strlen( option ) == n ) ) { if( val < 1 ) { fprintf( stderr, "Bad value for ALSA buffer size %i frames, using default (%d)\n", val, NUM_FRAMES ); } else { nperiods = val; } } else if( ( err = sscanf( option, " avail=%i %n%c", &val, &n, &tmp ) > 0 ) && ( tmp == ',' || strlen( option ) == n ) ) { if( val < 1 ) { fprintf( stderr, "Bad value for ALSA avail_min size %i frames, using default\n", val ); } else { avail_min = val; } } else if( ( err = sscanf( option, " verbose %n%c", &n, &tmp ) == 1 ) && ( tmp == ',' || strlen( option ) == n ) ) { verb = 1; } else { /* try as device name */ while( isspace(*option) ) option++; if( *option == '\'' ) /* force device... */ option++; pcm_name = option; n = strlen( pcm_name ); } option += n + ( tmp == ',' ); } /* Open the sound device */ if( pcm_name == NULL || *pcm_name == '\0' ) pcm_name = "default"; if( snd_pcm_open( &pcm_handle, pcm_name , stream, 0 ) < 0 ) { if( strcmp( pcm_name, "default" ) == 0 ) { /* we try a last one: plughw:0,0 but what a weired ALSA conf.... */ if( snd_pcm_open( &pcm_handle, "plughw:0,0", stream, 0 ) < 0 ) { settings_current.sound = 0; ui_error( UI_ERROR_ERROR, "couldn't open sound device 'default' and 'plughw:0,0' check ALSA configuration." ); init_running = 0; return 1; } else { if( first_init ) fprintf( stderr, "Couldn't open sound device 'default', using 'plughw:0,0' check ALSA configuration.\n" ); } } settings_current.sound = 0; ui_error( UI_ERROR_ERROR, "couldn't open sound device '%s'.", pcm_name ); init_running = 0; return 1; } /* Allocate the snd_pcm_hw_params_t structure on the stack. */ snd_pcm_hw_params_alloca( &hw_params ); /* Init hw_params with full configuration space */ if( snd_pcm_hw_params_any( pcm_handle, hw_params ) < 0 ) { settings_current.sound = 0; ui_error( UI_ERROR_ERROR, "couldn't get configuration space on sound device '%s'.", pcm_name ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } if( snd_pcm_hw_params_set_access( pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED ) < 0) { settings_current.sound = 0; ui_error( UI_ERROR_ERROR, "couldn't set access interleaved on '%s'.", pcm_name ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } /* Set sample format */ if( snd_pcm_hw_params_set_format( pcm_handle, hw_params, #if defined WORDS_BIGENDIAN SND_PCM_FORMAT_S16_BE #else SND_PCM_FORMAT_S16_LE #endif ) < 0 ) { settings_current.sound = 0; ui_error( UI_ERROR_ERROR, "couldn't set format on '%s'.", pcm_name ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } ch = *stereoptr ? 2 : 1; if( snd_pcm_hw_params_set_channels( pcm_handle, hw_params, ch ) < 0 ) { fprintf( stderr, "Couldn't set %s to '%s'.\n", pcm_name, (*stereoptr ? "stereo" : "mono") ); ch = *stereoptr ? 1 : 2; /* try with opposite */ if( snd_pcm_hw_params_set_channels( pcm_handle, hw_params, ch ) < 0 ) { ui_error( UI_ERROR_ERROR, "couldn't set %s to '%s'.", pcm_name, (*stereoptr ? "stereo" : "mono") ); settings_current.sound = 0; snd_pcm_close( pcm_handle ); init_running = 0; return 1; } *stereoptr = *stereoptr ? 0 : 1; /* write back */ } framesize = ch << 1; /* we always use 16 bit sorry :-( */ /* Set sample rate. If the exact rate is not supported */ /* by the hardware, use nearest possible rate. */ exact_rate = *freqptr; if( snd_pcm_hw_params_set_rate_near( pcm_handle, hw_params, &exact_rate, NULL ) < 0) { settings_current.sound = 0; ui_error( UI_ERROR_ERROR, "couldn't set rate %d on '%s'.", *freqptr, pcm_name ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } if( first_init && *freqptr != exact_rate ) { fprintf( stderr, "The rate %d Hz is not supported by your hardware. " "Using %d Hz instead.\n", *freqptr, exact_rate ); *freqptr = exact_rate; } if( bsize != 0 ) { exact_periodsize = sound_periodsize = bsize / nperiods; if( bsize < 1 ) { fprintf( stderr, "bad value for ALSA buffer size %i, using default.\n", val ); bsize = 0; } } if( bsize == 0 ) { hz = (float)machine_current->timings.processor_speed / machine_current->timings.tstates_per_frame; exact_periodsize = sound_periodsize = *freqptr / hz; } dir = -1; if( snd_pcm_hw_params_set_period_size_near( pcm_handle, hw_params, &exact_periodsize, &dir ) < 0 ) { settings_current.sound = 0; ui_error( UI_ERROR_ERROR, "couldn't set period size %d on '%s'.", (int)sound_periodsize, pcm_name ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } if( first_init && ( exact_periodsize < sound_periodsize / 1.5 || exact_periodsize > sound_periodsize * 1.5 ) ) { fprintf( stderr, "The period size %d is not supported by your hardware. " "Using %d instead.\n", (int)sound_periodsize, (int)exact_periodsize ); } periods = nperiods; /* Set number of periods. Periods used to be called fragments. */ if( snd_pcm_hw_params_set_periods_near( pcm_handle, hw_params, &periods, NULL ) < 0 ) { settings_current.sound = 0; ui_error( UI_ERROR_ERROR, "couldn't set periods on '%s'.", pcm_name ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } if( first_init && periods != nperiods ) { fprintf( stderr, "%d periods is not supported by your hardware. " "Using %d instead.\n", nperiods, periods ); } snd_pcm_hw_params_get_buffer_size( hw_params, &exact_bsize ); /* Apply HW parameter settings to */ /* PCM device and prepare device */ if( snd_pcm_hw_params( pcm_handle, hw_params ) < 0 ) { settings_current.sound = 0; ui_error( UI_ERROR_ERROR,"couldn't set hw_params on %s", pcm_name ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } snd_pcm_sw_params_alloca( &sw_params ); if( ( err = snd_pcm_sw_params_current( pcm_handle, sw_params ) ) < 0 ) { ui_error( UI_ERROR_ERROR,"couldn't get sw_params from %s: %s", pcm_name, snd_strerror ( err ) ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } if( ( err = snd_pcm_sw_params_set_start_threshold( pcm_handle, sw_params, exact_periodsize * ( nperiods - 1 ) ) ) < 0 ) { ui_error( UI_ERROR_ERROR,"couldn't set start_treshold on %s: %s", pcm_name, snd_strerror ( err ) ); snd_pcm_close( pcm_handle ); init_running = 0; return 1; } if( !avail_min ) avail_min = exact_periodsize >> 1; if( snd_pcm_sw_params_set_avail_min( pcm_handle, sw_params, avail_min ) < 0 ) { #if SND_LIB_VERSION < 0x10010 if( ( err = snd_pcm_sw_params_set_sleep_min( pcm_handle, sw_params, 1 ) ) < 0 ) { fprintf( stderr, "Unable to set minimal sleep 1 for %s: %s\n", pcm_name, snd_strerror ( err ) ); } #else fprintf( stderr, "Unable to set avail min %s: %s\n", pcm_name, snd_strerror( err ) ); #endif } #if SND_LIB_VERSION < 0x10010 if( ( err = snd_pcm_sw_params_set_xfer_align( pcm_handle, sw_params, 1 ) ) < 0 ) { ui_error( UI_ERROR_ERROR,"couldn't set xfer_allign on %s: %s", pcm_name, snd_strerror ( err ) ); init_running = 0; return 1; } #endif if( ( err = snd_pcm_sw_params( pcm_handle, sw_params ) ) < 0 ) { ui_error( UI_ERROR_ERROR,"couldn't set sw_params on %s: %s", pcm_name, snd_strerror ( err ) ); init_running = 0; return 1; } if( first_init ) snd_output_stdio_attach(&output, stdout, 0); first_init = 0; init_running = 0; return 0; /* success */ }
bool QAudioInputPrivate::open( QObject *input ) { // Open the Alsa capture device. bool rc = true; int err; unsigned int freakuency = frequency; if ((err = snd_pcm_open(&handle, m_device.constData(), //"plughw:0,0" SND_PCM_STREAM_CAPTURE, 0/*SND_PCM_ASYNC*/)) < 0) { qWarning( "QAudioInput: snd_pcm_open: error %d", err); rc = false; } else { snd_pcm_hw_params_t *hwparams; // We want non-blocking mode. snd_pcm_nonblock(handle, 1); // Set the desired parameters. snd_pcm_hw_params_alloca(&hwparams); err = snd_pcm_hw_params_any(handle, hwparams); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_any: err %d", err); } err = snd_pcm_hw_params_set_access(handle, hwparams, access); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_access: err %d",err); } err = snd_pcm_hw_params_set_format(handle, hwparams,format); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_format: err %d",err); } err = snd_pcm_hw_params_set_channels(handle,hwparams,(unsigned int)channels); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_channels: err %d",err); } err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &freakuency, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_rate_near: err %d",err); } if(freakuency > 1.05 * frequency || freakuency < 0.95 * frequency) { qWarning("QAudioInput: warning, sample rate %i not supported by the hardware, using %u", frequency, freakuency); } if ( samplesPerBlock != -1 ) { // Set buffer and period sizes based on the supplied block size. sample_size = (snd_pcm_uframes_t)( samplesPerBlock * channels / 8 ); err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &freakuency, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_rate_near: err %d",err); } if(freakuency > 1.05 * frequency || freakuency < 0.95 * frequency) { qWarning( "QAudioInput: warning, sample rate %i not supported by the hardware, using %u", frequency, freakuency); } err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err %d",err); } period_time = 1000000 * 256 / frequency; err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_period_time_near: err %d",err); } } else { // Use the largest buffer and period sizes we can. err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err %d",err); } period_time = 1000000 * 256 / frequency; err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_period_time_near: err %d",err); } } err = snd_pcm_hw_params(handle, hwparams); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params: err %d",err); } int dir; unsigned int vval, vval2; snd_pcm_access_t aval; snd_pcm_format_t fval; snd_pcm_subformat_t sval; qLog(QAudioInput) << "PCM handle name = " << snd_pcm_name(handle); qLog(QAudioInput) << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle)); snd_pcm_hw_params_get_access(hwparams,&aval); vval = (unsigned int)aval; if ( (int)vval != (int)access ) { qLog(QAudioInput) << QString("access type not set, want %1 got %2") .arg(snd_pcm_access_name((snd_pcm_access_t)access)) .arg(snd_pcm_access_name((snd_pcm_access_t)vval)); access = (snd_pcm_access_t)vval; } qLog(QAudioInput) << "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 ) { qLog(QAudioInput) << QString("format type not set, want %1 got %2") .arg(snd_pcm_format_name((snd_pcm_format_t)format)) .arg(snd_pcm_format_name((snd_pcm_format_t)vval)); format = (snd_pcm_format_t)vval; } qLog(QAudioInput) << 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(QAudioInput) << 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 ) { qLog(QAudioInput) << QString("channels type not set, want %1 got %2").arg(channels).arg(vval); channels = vval; } qLog(QAudioInput) << "channels = " << vval; snd_pcm_hw_params_get_rate(hwparams, &vval, &dir); if ( (int)vval != (int)frequency ) { qLog(QAudioInput) << QString("frequency type not set, want %1 got %2").arg(frequency).arg(vval); frequency = vval; } qLog(QAudioInput) << "rate =" << vval << " bps"; snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); qLog(QAudioInput) << "period time =" << period_time << " us"; snd_pcm_hw_params_get_period_size(hwparams,&period_size, &dir); qLog(QAudioInput) << "period size =" << (int)period_size; snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir); qLog(QAudioInput) << "buffer time =" << buffer_time; snd_pcm_hw_params_get_buffer_size(hwparams,(snd_pcm_uframes_t *) &buffer_size); qLog(QAudioInput) << "buffer size =" << (int)buffer_size; snd_pcm_hw_params_get_periods(hwparams, &vval, &dir); qLog(QAudioInput) << "periods per buffer =" << vval; snd_pcm_hw_params_get_rate_numden(hwparams, &vval, &vval2); qLog(QAudioInput) << QString("exact rate = %1/%2 bps").arg(vval).arg(vval2).toLatin1().constData(); vval = snd_pcm_hw_params_get_sbits(hwparams); qLog(QAudioInput) << "significant bits =" << vval; snd_pcm_hw_params_get_tick_time(hwparams,&vval, &dir); qLog(QAudioInput) << "tick time =" << vval; vval = snd_pcm_hw_params_is_batch(hwparams); qLog(QAudioInput) << "is batch =" << vval; vval = snd_pcm_hw_params_is_block_transfer(hwparams); qLog(QAudioInput) << "is block transfer =" << vval; vval = snd_pcm_hw_params_is_double(hwparams); qLog(QAudioInput) << "is double =" << vval; vval = snd_pcm_hw_params_is_half_duplex(hwparams); qLog(QAudioInput) << "is half duplex =" << vval; vval = snd_pcm_hw_params_is_joint_duplex(hwparams); qLog(QAudioInput) << "is joint duplex =" << vval; vval = snd_pcm_hw_params_can_overrange(hwparams); qLog(QAudioInput) << "can overrange =" << vval; vval = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams); qLog(QAudioInput) << "can mmap =" << vval; vval = snd_pcm_hw_params_can_pause(hwparams); qLog(QAudioInput) << "can pause =" << vval; vval = snd_pcm_hw_params_can_resume(hwparams); qLog(QAudioInput) << "can resume =" << vval; vval = snd_pcm_hw_params_can_sync_start(hwparams); qLog(QAudioInput) << "can sync start =" << vval; snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_sw_params_current(handle, swparams); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params_current: err %d",err); } err = snd_pcm_sw_params_set_start_threshold(handle,swparams,period_size); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params_set_start_threshold: err %d",err); } err = snd_pcm_sw_params_set_avail_min(handle, swparams,period_size); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params_set_avail_min: err %d",err); } err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params_set_xfer_align: err %d",err); } err = snd_pcm_sw_params(handle, swparams); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params: err %d",err); } snd_pcm_prepare(handle); snd_pcm_start(handle); int count = snd_pcm_poll_descriptors_count(handle); pollfd *pfds = new pollfd[count]; snd_pcm_poll_descriptors(handle, pfds, count); for (int i = 0; i < count; ++i) { if ((pfds[i].events & POLLIN) != 0) { notifier = new QSocketNotifier(pfds[i].fd, QSocketNotifier::Read); QObject::connect(notifier, SIGNAL(activated(int)), input, SIGNAL(readyRead())); break; } } if (notifier == NULL) { rc = false; } delete pfds; } return rc; }
static int sndo_pcm_initialize(sndo_pcm_t *pcm) { int err; snd_pcm_uframes_t boundary; snd_pcm_uframes_t p_period_size = ~0UL, c_period_size = ~0UL; snd_pcm_uframes_t p_buffer_size = ~0UL, c_buffer_size = ~0UL; if (pcm->playback) { err = snd_pcm_hw_params(pcm->playback, pcm->p_hw_params); if (err < 0) return err; err = snd_pcm_hw_params_get_period_size(pcm->p_hw_params, &p_period_size, NULL); if (err < 0) return err; err = snd_pcm_hw_params_get_buffer_size(pcm->p_hw_params, &p_buffer_size); if (err < 0) return err; } if (pcm->capture) { err = snd_pcm_hw_params(pcm->capture, pcm->c_hw_params); if (err < 0) return err; err = snd_pcm_hw_params_get_period_size(pcm->c_hw_params, &c_period_size, NULL); if (err < 0) return err; err = snd_pcm_hw_params_get_buffer_size(pcm->c_hw_params, &c_buffer_size); if (err < 0) return err; } if (p_period_size < c_period_size) pcm->transfer_block = p_period_size; else pcm->transfer_block = c_period_size; if (p_buffer_size < c_buffer_size) pcm->ring_size = p_buffer_size; else pcm->ring_size = c_buffer_size; if (pcm->playback) { err = snd_pcm_sw_params_get_boundary(pcm->p_sw_params, &boundary); if (err < 0) return err; err = snd_pcm_sw_params_set_start_threshold(pcm->playback, pcm->p_sw_params, boundary); if (err < 0) return err; err = snd_pcm_sw_params_set_stop_threshold(pcm->playback, pcm->p_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size); if (err < 0) return err; err = snd_pcm_sw_params_set_xfer_align(pcm->playback, pcm->p_sw_params, 1); if (err < 0) return err; err = snd_pcm_sw_params_set_avail_min(pcm->playback, pcm->p_sw_params, pcm->transfer_block); if (err < 0) return err; err = snd_pcm_sw_params(pcm->playback, pcm->p_sw_params); if (err < 0) return err; } if (pcm->capture) { err = snd_pcm_sw_params_get_boundary(pcm->c_sw_params, &boundary); if (err < 0) return err; err = snd_pcm_sw_params_set_start_threshold(pcm->capture, pcm->c_sw_params, boundary); if (err < 0) return err; err = snd_pcm_sw_params_set_stop_threshold(pcm->capture, pcm->c_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size); if (err < 0) return err; err = snd_pcm_sw_params_set_xfer_align(pcm->capture, pcm->c_sw_params, 1); if (err < 0) return err; err = snd_pcm_sw_params_set_avail_min(pcm->capture, pcm->c_sw_params, pcm->transfer_block); if (err < 0) return err; err = snd_pcm_sw_params(pcm->capture, pcm->c_sw_params); if (err < 0) return err; } pcm->initialized = 1; return 0; }
static int pcm_open(pcm_handle_t* pcm, const pcm_desc_t* desc) { const snd_pcm_format_t fmt = SND_PCM_FORMAT_S16_LE; snd_pcm_stream_t stm; int err; if (desc->flags & PCM_FLAG_IN) stm = SND_PCM_STREAM_CAPTURE; else stm = SND_PCM_STREAM_PLAYBACK; err = snd_pcm_open (&pcm->pcm, desc->name, stm, SND_PCM_NONBLOCK); if (err) PERROR_GOTO(snd_strerror(err), on_error_0); err = snd_pcm_hw_params_malloc(&pcm->hw_params); if (err) PERROR_GOTO(snd_strerror(err), on_error_1); err = snd_pcm_hw_params_any(pcm->pcm, pcm->hw_params); if (err) PERROR_GOTO(snd_strerror(err), on_error_2); err = snd_pcm_hw_params_set_access (pcm->pcm, pcm->hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err) PERROR_GOTO(snd_strerror(err), on_error_2); err = snd_pcm_hw_params_set_format(pcm->pcm, pcm->hw_params, fmt); if (err) PERROR_GOTO(snd_strerror(err), on_error_2); err = snd_pcm_hw_params_set_rate (pcm->pcm, pcm->hw_params, desc->fsampl, 0); if (err) PERROR_GOTO(snd_strerror(err), on_error_2); pcm->nchan = desc->nchan; pcm->wchan = (size_t)snd_pcm_format_physical_width(fmt) / 8; pcm->scale = pcm->nchan * pcm->wchan; err = snd_pcm_hw_params_set_channels (pcm->pcm, pcm->hw_params, desc->nchan); if (err) PERROR_GOTO(snd_strerror(err), on_error_2); err = snd_pcm_hw_params(pcm->pcm, pcm->hw_params); if (err) PERROR_GOTO(snd_strerror(err), on_error_2); err = snd_pcm_sw_params_malloc(&pcm->sw_params); if (err) PERROR_GOTO(snd_strerror(err), on_error_2); err = snd_pcm_sw_params_current(pcm->pcm, pcm->sw_params); if (err) PERROR_GOTO(snd_strerror(err), on_error_3); #if 1 err = snd_pcm_sw_params_set_avail_min (pcm->pcm, pcm->sw_params, 1024); if (err) PERROR_GOTO(snd_strerror(err), on_error_3); #endif #if 1 err = snd_pcm_sw_params_set_start_threshold (pcm->pcm, pcm->sw_params, 0U); if (err) PERROR_GOTO(snd_strerror(err), on_error_3); #endif err = snd_pcm_sw_params(pcm->pcm, pcm->sw_params); if (err) PERROR_GOTO(snd_strerror(err), on_error_3); err = snd_pcm_prepare(pcm->pcm); if (err) PERROR_GOTO(snd_strerror(err), on_error_3); pcm->rpos = 0; pcm->wpos = 0; pcm->nsampl = (size_t)desc->fsampl * 10; pcm->buf = malloc(pcm->nsampl * pcm->scale); if (pcm->buf == NULL) goto on_error_3; return 0; on_error_3: snd_pcm_sw_params_free(pcm->sw_params); on_error_2: snd_pcm_hw_params_free(pcm->hw_params); on_error_1: snd_pcm_close(pcm->pcm); on_error_0: return -1; }
/*---------------------------------------------------------------- TIesrFA_ALSA_open Try to open an ALSA audio PCM channel. ----------------------------------------------------------------*/ TIesrFA_ALSA_Error_t TIesrFA_ALSA_open( TIesrFA_t * const aTIesrFAInstance ) { int rtnStatus; int openSuccess = 0; snd_pcm_uframes_t numSamples; snd_pcm_hw_params_t *hw_params = 0; snd_pcm_sw_params_t *sw_params = 0; TIesrFA_ALSA_t * const ALSAData = (TIesrFA_ALSA_t * const) aTIesrFAInstance->impl_data; /* Try to open a handle to the ALSA pcm in blocking mode. */ rtnStatus = snd_pcm_open( &ALSAData->alsa_handle, aTIesrFAInstance->channel_name, SND_PCM_STREAM_CAPTURE, 0 ); if( rtnStatus < 0 ) goto openExit; /* Set up the information for recording from the audio channelport. This will include data specified by the user, such as data in aTIesrFAInstance->encoding, etc. If setup fails, then the audio channel should be shut down and failure reported. */ /* Setup hardware parameters of the ALSA pcm */ rtnStatus = snd_pcm_hw_params_malloc( &hw_params ); if( rtnStatus < 0 ) goto openExit; rtnStatus = snd_pcm_hw_params_any( ALSAData->alsa_handle, hw_params ); if( rtnStatus < 0 ) goto openExit; /* There will only be a single channel */ rtnStatus = snd_pcm_hw_params_set_channels( ALSAData->alsa_handle, hw_params, 1 ); if( rtnStatus < 0 ) goto openExit; /* Even though only one channel, must specify type of read. */ rtnStatus = snd_pcm_hw_params_set_access( ALSAData->alsa_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED ); if( rtnStatus < 0 ) goto openExit; /* Format type - only 16 bit linear for now */ rtnStatus = snd_pcm_hw_params_set_format( ALSAData->alsa_handle, hw_params, SND_PCM_FORMAT_S16 ); if( rtnStatus < 0 ) goto openExit; /* Set sample rate, it must be exactly supported */ rtnStatus = snd_pcm_hw_params_set_rate( ALSAData->alsa_handle, hw_params, aTIesrFAInstance->sample_rate, 0 ); if( rtnStatus < 0 ) goto openExit; /* Size of ALSA PCM ring buffer is set to approximately the desired number of multiples of read_samples in the buffer */ numSamples = aTIesrFAInstance->num_audio_buffer_frames * ALSAData->read_samples; rtnStatus = snd_pcm_hw_params_set_buffer_size_near( ALSAData->alsa_handle, hw_params, &numSamples ); if( rtnStatus < 0 ) goto openExit; /* Set the hardware parameters in the PCM*/ rtnStatus = snd_pcm_hw_params( ALSAData->alsa_handle, hw_params ); if( rtnStatus < 0 ) goto openExit; /* Set software parameters to interrupt at the end of an audio buffer number of samples and to start-up manually */ rtnStatus = snd_pcm_sw_params_malloc( &sw_params ); if( rtnStatus < 0 ) goto openExit; rtnStatus = snd_pcm_sw_params_current( ALSAData->alsa_handle, sw_params ); if( rtnStatus < 0 ) goto openExit; /* Number of samples needed in PCM buffer prior to interrupt */ rtnStatus = snd_pcm_sw_params_set_avail_min( ALSAData->alsa_handle, sw_params, ALSAData->read_samples ); if( rtnStatus < 0 ) goto openExit; /* Set start threshold so startup is done manually */ rtnStatus = snd_pcm_sw_params_set_start_threshold( ALSAData->alsa_handle, sw_params, ULONG_MAX ); if( rtnStatus < 0 ) goto openExit; /* Channel opened successfully */ openSuccess = 1; openExit: if( hw_params != NULL ) snd_pcm_hw_params_free( hw_params ); if( sw_params != NULL ) snd_pcm_sw_params_free( sw_params ); if( openSuccess ) return TIesrFA_ALSAErrNone; return TIesrFA_ALSAErrFail; }
int setparams_set(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_sw_params_t *swparams, const char *id) { int err; snd_pcm_uframes_t val; unsigned int sleep_min = 0; err = snd_pcm_hw_params(handle, params); if (err < 0) { printf("Unable to set hw params for %s: %s\n", id, snd_strerror(err)); return err; } err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { printf("Unable to determine current swparams for %s: %s\n", id, snd_strerror(err)); return err; } err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0x7fffffff); if (err < 0) { printf("Unable to set start threshold mode for %s: %s\n", id, snd_strerror(err)); return err; } tick_time_ok = 0; if (tick_time > 0) { int time, ttime; snd_pcm_hw_params_get_period_time(params, &time, NULL); snd_pcm_hw_params_get_tick_time(params, &ttime, NULL); if (time < ttime) { printf("Skipping to set minimal sleep: period time < tick time\n"); } else if (ttime <= 0) { printf("Skipping to set minimal sleep: tick time <= 0 (%i)\n", ttime); } else { sleep_min = tick_time / ttime; if (sleep_min <= 0) sleep_min = 1; err = snd_pcm_sw_params_set_sleep_min(handle, swparams, sleep_min); if (err < 0) { printf("Unable to set minimal sleep %i for %s: %s\n", sleep_min, id, snd_strerror(err)); return err; } tick_time_ok = sleep_min * ttime; } } if (!block) val = 4; else snd_pcm_hw_params_get_period_size(params, &val, NULL); if (tick_time_ok > 0) val = 16; err = snd_pcm_sw_params_set_avail_min(handle, swparams, val); if (err < 0) { printf("Unable to set avail min for %s: %s\n", id, snd_strerror(err)); return err; } val = !block ? 4 : 1; err = snd_pcm_sw_params_set_xfer_align(handle, swparams, val); if (err < 0) { printf("Unable to set transfer align for %s: %s\n", id, snd_strerror(err)); return err; } err = snd_pcm_sw_params(handle, swparams); if (err < 0) { printf("Unable to set sw params for %s: %s\n", id, snd_strerror(err)); return err; } return 0; }
/** * This method prepares ALSA system for 22050hz signed 16bits Little Endian * playback. */ void SoundThread::initAlsa() { int err; ostringstream oss; /* Get a handle on the PCM device. */ if ((err = snd_pcm_open (&playback_handle, deviceName, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { oss << "cannot open audio device : " << deviceName << snd_strerror(err) << endl; throw oss.str(); } /* Allocate snd_pcm_hw_params_t structure. */ if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { oss << "cannot allocate hardware parameter structure : " << snd_strerror (err) << endl; throw oss.str(); } /* Retrieve current parameters. */ if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) { oss << "cannot initialize hardware parameter structure : " << snd_strerror (err) << endl; throw oss.str(); } /* Set Sample are NON Interleaved (mono !) */ if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED)) < 0) { oss << "cannot set access type : " << snd_strerror (err) << endl; throw oss.str(); } /* Set Sample format: Signed 16bit little endian. */ if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { oss << "cannot set sample format : " << snd_strerror (err) << endl; throw oss.str(); } /* Set the Sample rate. */ if ((err = snd_pcm_hw_params_set_rate (playback_handle, hw_params, 22050, 0)) < 0) { oss << "cannot set sample rate : " << snd_strerror (err) << endl; throw oss.str(); } /* Set Channel number (MONO). */ if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 1)) < 0) { oss << "cannot set channel count : " << snd_strerror (err) << endl; throw oss.str(); } if ((err = snd_pcm_hw_params_set_buffer_size(playback_handle, hw_params, 2048)) < 0) { oss << "cannot set channel buffer size : " << snd_strerror (err) << endl; throw oss.str(); } /* Apply these parameters. */ if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) { oss << "cannot apply parameters : " << snd_strerror (err) << endl; throw oss.str(); } snd_pcm_uframes_t bufferSize; snd_pcm_hw_params_get_buffer_size( hw_params, &bufferSize ); //cout << "initAlsa: Buffer size = " << bufferSize << " frames." << endl; /* Free memoray allocated for snd_pcm_hw_params_t */ snd_pcm_hw_params_free (hw_params); /* tell ALSA to wake us up whenever 4096 or more frames of playback data can be delivered. Also, tell ALSA that we'll start the device ourselves. */ /* Allocate snd_pcm_sw_params_t structure. */ if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { oss << "cannot allocate software parameters structure : " << snd_strerror (err) << endl; throw oss.str(); } /* Get the current software configuration*/ if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0) { oss << "cannot initialize software parameters structure : " << snd_strerror (err) << endl; throw oss.str(); } /* Set the wake up point to 2048 (92.9 ms). The minimum data available before asking*/ /* for new ones. */ if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 2048U)) < 0) { oss << "cannot set minimum available count : " << snd_strerror (err) << endl; throw oss.str(); } /* Set when ALSA starts to play. */ if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 1024U)) < 0) { oss << "cannot set start mode : " << snd_strerror (err) << endl; throw oss.str(); } /* Apply parameters. */ if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0) { oss << "cannot apply software parameters : " << snd_strerror (err) << endl; throw oss.str(); } /* the interface will interrupt the kernel every 4096 frames, and ALSA will wake up this program very soon after that. */ if ((err = snd_pcm_prepare (playback_handle)) < 0) { oss << "cannot prepare audio interface for use : " << snd_strerror (err) << endl; throw oss.str(); } }
static boolean tsmf_alsa_set_format(ITSMFAudioDevice* audio, uint32 sample_rate, uint32 channels, uint32 bits_per_sample) { int error; snd_pcm_uframes_t frames; snd_pcm_hw_params_t* hw_params; snd_pcm_sw_params_t* sw_params; TSMFALSAAudioDevice* alsa = (TSMFALSAAudioDevice*) audio; if (!alsa->out_handle) return false; snd_pcm_drop(alsa->out_handle); alsa->actual_rate = alsa->source_rate = sample_rate; alsa->actual_channels = alsa->source_channels = channels; alsa->bytes_per_sample = bits_per_sample / 8; error = snd_pcm_hw_params_malloc(&hw_params); if (error < 0) { DEBUG_WARN("snd_pcm_hw_params_malloc failed"); return false; } snd_pcm_hw_params_any(alsa->out_handle, hw_params); snd_pcm_hw_params_set_access(alsa->out_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(alsa->out_handle, hw_params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params, &alsa->actual_rate, NULL); snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params, &alsa->actual_channels); frames = sample_rate; snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params, &frames); snd_pcm_hw_params(alsa->out_handle, hw_params); snd_pcm_hw_params_free(hw_params); error = snd_pcm_sw_params_malloc(&sw_params); if (error < 0) { DEBUG_WARN("snd_pcm_sw_params_malloc"); return false; } snd_pcm_sw_params_current(alsa->out_handle, sw_params); snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, frames / 2); snd_pcm_sw_params(alsa->out_handle, sw_params); snd_pcm_sw_params_free(sw_params); snd_pcm_prepare(alsa->out_handle); DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d", sample_rate, channels, bits_per_sample); DEBUG_DVC("hardware buffer %d frames", (int)frames); if ((alsa->actual_rate != alsa->source_rate) || (alsa->actual_channels != alsa->source_channels)) { DEBUG_DVC("actual rate %d / channel %d is different " "from source rate %d / channel %d, resampling required.", alsa->actual_rate, alsa->actual_channels, alsa->source_rate, alsa->source_channels); } return true; }
AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period) { int dir; int err; snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; snd_pcm_uframes_t period_size = period; snd_pcm_uframes_t buffer_size = PERIODS*period; static snd_output_t *jcd_out; AlsaDevice *dev = malloc(sizeof(*dev)); if (!dev) return NULL; dev->device_name = malloc(1+strlen(device_name)); if (!dev->device_name) { free(dev); return NULL; } strcpy(dev->device_name, device_name); dev->channels = channels; dev->period = period; err = snd_output_stdio_attach(&jcd_out, stdout, 0); if ((err = snd_pcm_open (&dev->capture_handle, dev->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", dev->device_name, snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_any (dev->capture_handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_access (dev->capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_format (dev->capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_rate_near (dev->capture_handle, hw_params, &rate, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); assert(0); } /*fprintf (stderr, "rate = %d\n", rate);*/ if ((err = snd_pcm_hw_params_set_channels (dev->capture_handle, hw_params, channels)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); assert(0); } period_size = period; dir = 0; if ((err = snd_pcm_hw_params_set_period_size_near (dev->capture_handle, hw_params, &period_size, &dir)) < 0) { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_periods (dev->capture_handle, hw_params, PERIODS, 0)) < 0) { fprintf (stderr, "cannot set number of periods (%s)\n", snd_strerror (err)); assert(0); } buffer_size = period_size * PERIODS; dir=0; if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->capture_handle, hw_params, &buffer_size)) < 0) { fprintf (stderr, "cannot set buffer time (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params (dev->capture_handle, hw_params)) < 0) { fprintf (stderr, "cannot set capture parameters (%s)\n", snd_strerror (err)); assert(0); } /*snd_pcm_dump_setup(dev->capture_handle, jcd_out);*/ snd_pcm_hw_params_free (hw_params); if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { fprintf (stderr, "cannot allocate software parameters structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_current (dev->capture_handle, sw_params)) < 0) { fprintf (stderr, "cannot initialize software parameters structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_set_avail_min (dev->capture_handle, sw_params, period)) < 0) { fprintf (stderr, "cannot set minimum available count (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params (dev->capture_handle, sw_params)) < 0) { fprintf (stderr, "cannot set software parameters (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_open (&dev->playback_handle, dev->device_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", dev->device_name, snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_any (dev->playback_handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_access (dev->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_format (dev->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_rate_near (dev->playback_handle, hw_params, &rate, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); assert(0); } /*fprintf (stderr, "rate = %d\n", rate);*/ if ((err = snd_pcm_hw_params_set_channels (dev->playback_handle, hw_params, channels)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); assert(0); } period_size = period; dir = 0; if ((err = snd_pcm_hw_params_set_period_size_near (dev->playback_handle, hw_params, &period_size, &dir)) < 0) { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_periods (dev->playback_handle, hw_params, PERIODS, 0)) < 0) { fprintf (stderr, "cannot set number of periods (%s)\n", snd_strerror (err)); assert(0); } buffer_size = period_size * PERIODS; dir=0; if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->playback_handle, hw_params, &buffer_size)) < 0) { fprintf (stderr, "cannot set buffer time (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params (dev->playback_handle, hw_params)) < 0) { fprintf (stderr, "cannot set playback parameters (%s)\n", snd_strerror (err)); assert(0); } /*snd_pcm_dump_setup(dev->playback_handle, jcd_out);*/ snd_pcm_hw_params_free (hw_params); if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { fprintf (stderr, "cannot allocate software parameters structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_current (dev->playback_handle, sw_params)) < 0) { fprintf (stderr, "cannot initialize software parameters structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_set_avail_min (dev->playback_handle, sw_params, period)) < 0) { fprintf (stderr, "cannot set minimum available count (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_set_start_threshold (dev->playback_handle, sw_params, period)) < 0) { fprintf (stderr, "cannot set start mode (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params (dev->playback_handle, sw_params)) < 0) { fprintf (stderr, "cannot set software parameters (%s)\n", snd_strerror (err)); assert(0); } snd_pcm_link(dev->capture_handle, dev->playback_handle); if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); assert(0); } dev->readN = snd_pcm_poll_descriptors_count(dev->capture_handle); dev->writeN = snd_pcm_poll_descriptors_count(dev->playback_handle); dev->read_fd = malloc(dev->readN*sizeof(*dev->read_fd)); /*printf ("descriptors: %d %d\n", dev->readN, dev->writeN);*/ if (snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd, dev->readN) != dev->readN) { fprintf (stderr, "cannot obtain capture file descriptors (%s)\n", snd_strerror (err)); assert(0); } dev->write_fd = malloc(dev->writeN*sizeof(*dev->read_fd)); if (snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd, dev->writeN) != dev->writeN) { fprintf (stderr, "cannot obtain playback file descriptors (%s)\n", snd_strerror (err)); assert(0); } return dev; }
void ags_devout_alsa_init(AgsDevout *devout, GError **error) { static unsigned int period_time = 100000; static snd_pcm_format_t format = SND_PCM_FORMAT_S16; int rc; snd_pcm_t *handle; snd_pcm_hw_params_t *hwparams; unsigned int val; snd_pcm_uframes_t frames; unsigned int rate; unsigned int rrate; unsigned int channels; snd_pcm_uframes_t size; snd_pcm_sframes_t buffer_size; snd_pcm_sframes_t period_size; snd_pcm_sw_params_t *swparams; int period_event = 0; int err, dir; /* Open PCM device for playback. */ if ((err = snd_pcm_open(&handle, devout->out.alsa.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); return; } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); /* choose all parameters */ err = snd_pcm_hw_params_any(handle, hwparams); if (err < 0) { printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); return; } /* set hardware resampling */ err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 1); if (err < 0) { printf("Resampling setup failed for playback: %s\n", snd_strerror(err)); return; } /* set the interleaved read/write format */ err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { printf("Access type not available for playback: %s\n", snd_strerror(err)); return; } /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, hwparams, format); if (err < 0) { printf("Sample format not available for playback: %s\n", snd_strerror(err)); return; } /* set the count of channels */ channels = devout->dsp_channels; err = snd_pcm_hw_params_set_channels(handle, hwparams, channels); if (err < 0) { printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); return; } /* set the stream rate */ rate = devout->frequency; rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rrate, 0); if (err < 0) { printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); return; } if (rrate != rate) { printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); exit(-EINVAL); } /* set the buffer size */ size = devout->buffer_size; err = snd_pcm_hw_params_set_buffer_size(handle, hwparams, size); if (err < 0) { printf("Unable to set buffer size %i for playback: %s\n", size, snd_strerror(err)); return; } buffer_size = size; /* set the period time */ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); if (err < 0) { printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); return; } err = snd_pcm_hw_params_get_period_size(hwparams, &size, &dir); if (err < 0) { printf("Unable to get period size for playback: %s\n", snd_strerror(err)); return; } period_size = size; /* write the parameters to device */ err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); return; } /* get the current swparams */ err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err)); return; } /* start the transfer when the buffer is almost full: */ /* (buffer_size / avail_min) * avail_min */ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size); if (err < 0) { printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); return; } /* allow the transfer when at least period_size samples can be processed */ /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */ err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size); if (err < 0) { printf("Unable to set avail min for playback: %s\n", snd_strerror(err)); return; } /* write the parameters to the playback device */ err = snd_pcm_sw_params(handle, swparams); if (err < 0) { printf("Unable to set sw params for playback: %s\n", snd_strerror(err)); return; } /* */ devout->out.alsa.handle = handle; devout->delay_counter = 0; }
static int set_swparams (GstAlsaSink * alsa) { int err; snd_pcm_sw_params_t *params; snd_pcm_sw_params_malloc (¶ms); /* get the current swparams */ CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config); /* start the transfer when the buffer is almost full: */ /* (buffer_size / avail_min) * avail_min */ CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params, (alsa->buffer_size / alsa->period_size) * alsa->period_size), start_threshold); /* allow the transfer when at least period_size samples can be processed */ CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params, alsa->period_size), set_avail); #if GST_CHECK_ALSA_VERSION(1,0,16) /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */ #else /* align all transfers to 1 sample */ CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align); #endif /* write the parameters to the playback device */ CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params); snd_pcm_sw_params_free (params); return 0; /* ERRORS */ no_config: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to determine current swparams for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } start_threshold: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set start threshold mode for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } set_avail: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set avail min for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } #if !GST_CHECK_ALSA_VERSION(1,0,16) set_align: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set transfer align for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } #endif set_sw_params: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set sw params for playback: %s", snd_strerror (err))); snd_pcm_sw_params_free (params); return err; } }
bool WaveRecorder::init(uint32_t samples_per_sec, uint32_t bits_per_sample, uint32_t channels, uint32_t frame_size) { const char* pcm_device = "default"; snd_pcm_format_t format; int err; _frame_size = frame_size; switch (bits_per_sample) { case 8: format = SND_PCM_FORMAT_S8; break; case 16: format = SND_PCM_FORMAT_S16_LE; break; default: return false; } if ((err = snd_pcm_open(&_pcm, pcm_device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { LOG_ERROR("cannot open audio record device %s %s", pcm_device, snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_malloc(&_hw_params)) < 0) { LOG_ERROR("cannot allocate hardware parameter structure %s", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params_malloc(&_sw_params)) < 0) { LOG_ERROR("cannot allocate software parameter structure %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_any(_pcm, _hw_params)) < 0) { LOG_ERROR("cannot initialize hardware parameter structure %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_rate_resample(_pcm, _hw_params, 1)) < 0) { LOG_ERROR("cannot set rate resample %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_access(_pcm, _hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { LOG_ERROR("cannot set access type %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_rate(_pcm, _hw_params, samples_per_sec, 0)) < 0) { LOG_ERROR("cannot set sample rate %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_channels(_pcm, _hw_params, channels)) < 0) { LOG_ERROR("cannot set channel count %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_format(_pcm, _hw_params, format)) < 0) { LOG_ERROR("cannot set sample format %s", snd_strerror(err)); return false; } int direction = 0; snd_pcm_uframes_t buffer_size = (samples_per_sec * 160 / 1000) / frame_size * frame_size; if ((err = snd_pcm_hw_params_set_buffer_size_near(_pcm, _hw_params, &buffer_size)) < 0) { LOG_ERROR("cannot set buffer size %s", snd_strerror(err)); return false; } snd_pcm_uframes_t period_size = frame_size; if ((err = snd_pcm_hw_params_set_period_size_near(_pcm, _hw_params, &period_size, &direction)) < 0) { LOG_ERROR("cannot set period size near %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params(_pcm, _hw_params)) < 0) { LOG_ERROR("cannot set parameters %s", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params_current(_pcm, _sw_params)) < 0) { LOG_ERROR("cannot get current sw parameters %s", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params_set_start_threshold(_pcm, _sw_params, frame_size)) < 0) { LOG_ERROR("cannot set start threshold %s", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params(_pcm, _sw_params)) < 0) { LOG_ERROR("cannot set sw parameters %s", snd_strerror(err)); return false; } struct pollfd pfd; if ((err = snd_pcm_poll_descriptors(_pcm, &pfd, 1)) < 0) { LOG_ERROR("cannot get poll ID %s", snd_strerror(err)); return false; } _event_trigger = new WaveRecorder::EventTrigger(*this, pfd.fd); _client.add_event_source(*_event_trigger); return true; }
int ai_alsa_setup(audio_in_t *ai) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; int buffer_size; int err; 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_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig); return -1; } err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType); return -1; } err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE); if (err < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt); return -1; } err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); if (err < 0) { ai->channels = snd_pcm_hw_params_get_channels(params); mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount, ai->channels); } else { ai->channels = ai->req_channels; } err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, ai->req_samplerate, 0); assert(err >= 0); rate = err; ai->samplerate = rate; ai->alsa.buffer_time = 1000000; ai->alsa.buffer_time = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, ai->alsa.buffer_time, 0); assert(ai->alsa.buffer_time >= 0); ai->alsa.period_time = ai->alsa.buffer_time / 4; ai->alsa.period_time = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, ai->alsa.period_time, 0); assert(ai->alsa.period_time >= 0); err = snd_pcm_hw_params(ai->alsa.handle, params); if (err < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams); snd_pcm_hw_params_dump(params, ai->alsa.log); return -1; } ai->alsa.chunk_size = snd_pcm_hw_params_get_period_size(params, 0); buffer_size = snd_pcm_hw_params_get_buffer_size(params); if (ai->alsa.chunk_size == buffer_size) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size); return -1; } snd_pcm_sw_params_current(ai->alsa.handle, swparams); err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0); assert(err >= 0); err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); assert(err >= 0); err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); assert(err >= 0); err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); assert(err >= 0); assert(err >= 0); if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams); 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; }
void audio_init() { unsigned int buffer_time = 50000; const char* device; int err; if(audio_initialised) return; audio_initialised = 1; device = getenv("ALSA_DEVICE"); if(!device) device = "default"; if(0 > (err = snd_pcm_open(&playback_handle, device, SND_PCM_STREAM_PLAYBACK, 0/*SND_PCM_NONBLOCK*/))) errx(EXIT_FAILURE, "Audio: Cannot open device %s: %s", device, snd_strerror(err)); if(0 > (err = snd_pcm_sw_params_malloc(&sw_params))) errx(EXIT_FAILURE, "Audio: Could not allocate software parameter structure: %s", snd_strerror(err)); if(0 > (err = snd_pcm_hw_params_malloc(&hw_params))) errx(EXIT_FAILURE, "Audio: Could not allocate hardware parameter structure: %s", snd_strerror(err)); if(0 > (err = snd_pcm_hw_params_any(playback_handle, hw_params))) errx(EXIT_FAILURE, "Audio: Could not initializa hardware parameters: %s", snd_strerror(err)); if(0 > (err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED))) errx(EXIT_FAILURE, "Audio: Could not set access type: %s", snd_strerror(err)); if(0 > (err = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_S16))) errx(EXIT_FAILURE, "Audio: Could not set sample format to signed 16 bit " "native endian: %s", snd_strerror(err)); if(0 > (err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &rate, 0))) errx(EXIT_FAILURE, "Audio: Could not set sample rate %uHz: %s", rate, snd_strerror(err)); if(0 > (err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2))) errx(EXIT_FAILURE, "Audio: Could not set channel count to %u: %s", 2, snd_strerror(err)); snd_pcm_hw_params_set_buffer_time_near(playback_handle, hw_params, &buffer_time, 0); if(0 > (err = snd_pcm_hw_params(playback_handle, hw_params))) errx(EXIT_FAILURE, "Audio: Could not set hardware parameters: %s", snd_strerror(err)); fprintf(stderr, "Buffer time is %.3f seconds\n", buffer_time / 1.0e6); if(0 > (err = snd_pcm_sw_params_current(playback_handle, sw_params))) errx(EXIT_FAILURE, "Audio: Could not initialise software parameters: %s", snd_strerror(err)); snd_pcm_sw_params_set_start_threshold(playback_handle, sw_params, 0); snd_pcm_sw_params_set_avail_min(playback_handle, sw_params, 1024); snd_pcm_uframes_t min; snd_pcm_sw_params_get_avail_min(sw_params, &min); fprintf(stderr, "Minimum %u\n", (unsigned) min); if(0 > (err = snd_pcm_sw_params(playback_handle, sw_params))) errx(EXIT_FAILURE, "Audio: Could not set software parameters: %s", snd_strerror(err)); buffer_size = snd_pcm_avail_update(playback_handle); }
static void *alsa_init(const char *device, unsigned rate, unsigned latency) { alsa_t *alsa = (alsa_t*)calloc(1, sizeof(alsa_t)); if (!alsa) return NULL; snd_pcm_hw_params_t *params = NULL; snd_pcm_sw_params_t *sw_params = NULL; const char *alsa_dev = "default"; if (device) alsa_dev = device; unsigned latency_usec = latency * 1000 / 2; unsigned channels = 2; unsigned periods = 4; snd_pcm_uframes_t buffer_size; snd_pcm_format_t format; 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 = 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)); snd_pcm_hw_params_get_period_size(params, &alsa->period_frames, NULL); RARCH_LOG("ALSA: Period size: %d frames\n", (int)alsa->period_frames); snd_pcm_hw_params_get_buffer_size(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_free(alsa); return NULL; }
static void rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa) { snd_pcm_hw_params_t* hw_params; snd_pcm_sw_params_t* sw_params; int error; snd_pcm_uframes_t frames; snd_pcm_uframes_t start_threshold; snd_pcm_drop(alsa->out_handle); error = snd_pcm_hw_params_malloc(&hw_params); if (error < 0) { DEBUG_WARN("snd_pcm_hw_params_malloc failed"); return; } snd_pcm_hw_params_any(alsa->out_handle, hw_params); snd_pcm_hw_params_set_access(alsa->out_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(alsa->out_handle, hw_params, alsa->format); snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params, &alsa->actual_rate, NULL); snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params, &alsa->actual_channels); if (alsa->latency < 0) frames = alsa->actual_rate * 4; /* Default to 4-second buffer */ else frames = alsa->latency * alsa->actual_rate * 2 / 1000; /* Double of the latency */ if (frames < alsa->actual_rate / 2) frames = alsa->actual_rate / 2; /* Minimum 0.5-second buffer */ snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params, &frames); snd_pcm_hw_params(alsa->out_handle, hw_params); snd_pcm_hw_params_free(hw_params); error = snd_pcm_sw_params_malloc(&sw_params); if (error < 0) { DEBUG_WARN("snd_pcm_sw_params_malloc failed"); return; } snd_pcm_sw_params_current(alsa->out_handle, sw_params); if (alsa->latency == 0) start_threshold = 0; else start_threshold = frames / 2; snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, start_threshold); snd_pcm_sw_params(alsa->out_handle, sw_params); snd_pcm_sw_params_free(sw_params); snd_pcm_prepare(alsa->out_handle); DEBUG_SVC("hardware buffer %d frames, playback buffer %.2g seconds", (int)frames, (double)frames / 2.0 / (double)alsa->actual_rate); if ((alsa->actual_rate != alsa->source_rate) || (alsa->actual_channels != alsa->source_channels)) { DEBUG_SVC("actual rate %d / channel %d is different from source rate %d / channel %d, resampling required.", alsa->actual_rate, alsa->actual_channels, alsa->source_rate, alsa->source_channels); } }
main (int argc, char *argv[]) { snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; snd_pcm_sframes_t frames_to_deliver; int nfds; int err; struct pollfd *pfds; if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", argv[1], snd_strerror (err)); exit (1); } 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 (playback_handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, 44100, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)); exit (1); } snd_pcm_hw_params_free (hw_params); if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { fprintf (stderr, "cannot allocate software parameters structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0) { fprintf (stderr, "cannot initialize software parameters structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 4096)) < 0) { fprintf (stderr, "cannot set minimum available count (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 0U)) < 0) { fprintf (stderr, "cannot set start mode (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0) { fprintf (stderr, "cannot set software parameters (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_prepare (playback_handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); exit (1); } while (1) { if ((err = snd_pcm_wait (playback_handle, 1000)) < 0) { fprintf (stderr, "poll failed (%s)\n", strerror (errno)); break; } if ((frames_to_deliver = snd_pcm_avail_update (playback_handle)) < 0) { if (frames_to_deliver == -EPIPE) { fprintf (stderr, "an xrun occured\n"); break; } else { fprintf (stderr, "unknown ALSA avail update return value (%d)\n", frames_to_deliver); break; } } frames_to_deliver = frames_to_deliver > 4096 ? 4096 : frames_to_deliver; if (playback_callback (frames_to_deliver) != frames_to_deliver) { fprintf (stderr, "playback callback failed\n"); break; } } snd_pcm_close (playback_handle); exit (0); }
/* open & setup audio device return: 1=success 0=fail */ static int init(int rate_hz, int channels, int format, int flags) { unsigned int alsa_buffer_time = 500000; /* 0.5 s */ unsigned int alsa_fragcount = 16; int err; int block; strarg_t device; snd_pcm_uframes_t chunk_size; snd_pcm_uframes_t bufsize; snd_pcm_uframes_t boundary; const opt_t subopts[] = { {"block", OPT_ARG_BOOL, &block, NULL}, {"device", OPT_ARG_STR, &device, str_maxlen}, {NULL} }; char alsa_device[ALSA_DEVICE_SIZE + 1]; // make sure alsa_device is null-terminated even when using strncpy etc. memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1); mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz, channels, format); alsa_handler = NULL; #if SND_LIB_VERSION >= 0x010005 mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version()); #else mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR); #endif snd_lib_error_set_handler(alsa_error_handler); ao_data.samplerate = rate_hz; ao_data.format = format; ao_data.channels = channels; switch (format) { case AF_FORMAT_S8: alsa_format = SND_PCM_FORMAT_S8; break; case AF_FORMAT_U8: alsa_format = SND_PCM_FORMAT_U8; break; case AF_FORMAT_U16_LE: alsa_format = SND_PCM_FORMAT_U16_LE; break; case AF_FORMAT_U16_BE: alsa_format = SND_PCM_FORMAT_U16_BE; break; case AF_FORMAT_AC3_LE: case AF_FORMAT_S16_LE: case AF_FORMAT_IEC61937_LE: alsa_format = SND_PCM_FORMAT_S16_LE; break; case AF_FORMAT_AC3_BE: case AF_FORMAT_S16_BE: case AF_FORMAT_IEC61937_BE: alsa_format = SND_PCM_FORMAT_S16_BE; break; case AF_FORMAT_U32_LE: alsa_format = SND_PCM_FORMAT_U32_LE; break; case AF_FORMAT_U32_BE: alsa_format = SND_PCM_FORMAT_U32_BE; break; case AF_FORMAT_S32_LE: alsa_format = SND_PCM_FORMAT_S32_LE; break; case AF_FORMAT_S32_BE: alsa_format = SND_PCM_FORMAT_S32_BE; break; case AF_FORMAT_U24_LE: alsa_format = SND_PCM_FORMAT_U24_3LE; break; case AF_FORMAT_U24_BE: alsa_format = SND_PCM_FORMAT_U24_3BE; break; case AF_FORMAT_S24_LE: alsa_format = SND_PCM_FORMAT_S24_3LE; break; case AF_FORMAT_S24_BE: alsa_format = SND_PCM_FORMAT_S24_3BE; break; case AF_FORMAT_FLOAT_LE: alsa_format = SND_PCM_FORMAT_FLOAT_LE; break; case AF_FORMAT_FLOAT_BE: alsa_format = SND_PCM_FORMAT_FLOAT_BE; break; case AF_FORMAT_MU_LAW: alsa_format = SND_PCM_FORMAT_MU_LAW; break; case AF_FORMAT_A_LAW: alsa_format = SND_PCM_FORMAT_A_LAW; break; default: alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1 break; } //subdevice parsing // set defaults block = 1; /* switch for spdif * sets opening sequence for SPDIF * sets also the playback and other switches 'on the fly' * while opening the abstract alias for the spdif subdevice * 'iec958' */ if (AF_FORMAT_IS_IEC61937(format)) { device.str = "iec958"; mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n", channels); } else /* in any case for multichannel playback we should select * appropriate device */ switch (channels) { case 1: case 2: device.str = "default"; mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n"); break; case 4: if (alsa_format == SND_PCM_FORMAT_FLOAT_LE) // hack - use the converter plugin device.str = "plug:surround40"; else device.str = "surround40"; mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n"); break; case 6: if (alsa_format == SND_PCM_FORMAT_FLOAT_LE) device.str = "plug:surround51"; else device.str = "surround51"; mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n"); break; case 8: if (alsa_format == SND_PCM_FORMAT_FLOAT_LE) device.str = "plug:surround71"; else device.str = "surround71"; mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround71\n"); break; default: device.str = "default"; mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ChannelsNotSupported,channels); } device.len = strlen(device.str); if (subopt_parse(ao_subdevice, subopts) != 0) { print_help(); return 0; } parse_device(alsa_device, device.str, device.len); mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device); if (!alsa_handler) { int open_mode = block ? 0 : SND_PCM_NONBLOCK; int isac3 = AF_FORMAT_IS_IEC61937(format); //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC mp_msg(MSGT_AO,MSGL_V,"alsa-init: opening device in %sblocking mode\n", block ? "" : "non-"); if ((err = try_open_device(alsa_device, open_mode, isac3)) < 0) { if (err != -EBUSY && !block) { mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed); if ((err = try_open_device(alsa_device, 0, isac3)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err)); return 0; } } else { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err)); return 0; } } if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSetBlockMode, snd_strerror(err)); } else { mp_msg(MSGT_AO,MSGL_V,"alsa-init: device reopened in blocking mode\n"); } snd_pcm_hw_params_alloca(&alsa_hwparams); snd_pcm_sw_params_alloca(&alsa_swparams); // setting hw-parameters if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetInitialParameters, snd_strerror(err)); return 0; } err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetAccessType, snd_strerror(err)); return 0; } /* workaround for nonsupported formats sets default format to S16_LE if the given formats aren't supported */ if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams, alsa_format)) < 0) { mp_msg(MSGT_AO,MSGL_INFO, MSGTR_AO_ALSA_FormatNotSupportedByHardware, af_fmt2str_short(format)); alsa_format = SND_PCM_FORMAT_S16_LE; if (AF_FORMAT_IS_AC3(ao_data.format)) ao_data.format = AF_FORMAT_AC3_LE; else if (AF_FORMAT_IS_IEC61937(ao_data.format)) ao_data.format = AF_FORMAT_IEC61937_LE; else ao_data.format = AF_FORMAT_S16_LE; } if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams, alsa_format)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetFormat, snd_strerror(err)); return 0; } if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams, &ao_data.channels)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetChannels, snd_strerror(err)); return 0; } /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11) prefer our own resampler, since that allows users to choose the resampler, even per file if desired */ #if SND_LIB_VERSION >= 0x010009 if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams, 0)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToDisableResampling, snd_strerror(err)); return 0; } #endif if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, &ao_data.samplerate, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSamplerate2, snd_strerror(err)); return 0; } bytes_per_sample = af_fmt2bits(ao_data.format) / 8; bytes_per_sample *= ao_data.channels; ao_data.bps = ao_data.samplerate * bytes_per_sample; if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, &alsa_buffer_time, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetBufferTimeNear, snd_strerror(err)); return 0; } if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams, &alsa_fragcount, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriods, snd_strerror(err)); return 0; } /* finally install hardware parameters */ if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetHwParameters, snd_strerror(err)); return 0; } // end setting hw-params // gets buffersize for control if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBufferSize, snd_strerror(err)); return 0; } else { ao_data.buffersize = bufsize * bytes_per_sample; mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize); } if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetPeriodSize, snd_strerror(err)); return 0; } else { mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size); } ao_data.outburst = chunk_size * bytes_per_sample; /* setting software parameters */ if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters, snd_strerror(err)); return 0; } #if SND_LIB_VERSION >= 0x000901 if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBoundary, snd_strerror(err)); return 0; } #else boundary = 0x7fffffff; #endif /* start playing when one period has been written */ if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStartThreshold, snd_strerror(err)); return 0; } /* disable underrun reporting */ if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStopThreshold, snd_strerror(err)); return 0; } #if SND_LIB_VERSION >= 0x000901 /* play silence when there is an underrun */ if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSilenceSize, snd_strerror(err)); return 0; } #endif if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters, snd_strerror(err)); return 0; } /* end setting sw-params */ mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", ao_data.samplerate, ao_data.channels, (int)bytes_per_sample, ao_data.buffersize, snd_pcm_format_description(alsa_format)); } // end switch alsa_handler (spdif) alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams); return 1; } // end init
status_t setSoftwareParams(alsa_handle_t *handle) { snd_pcm_sw_params_t * softwareParams; int err; snd_pcm_uframes_t bufferSize = 0; snd_pcm_uframes_t periodSize = 0; snd_pcm_uframes_t startThreshold, stopThreshold; if (snd_pcm_sw_params_malloc(&softwareParams) < 0) { LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!"); return NO_INIT; } // Get the current software parameters err = snd_pcm_sw_params_current(handle->handle, softwareParams); if (err < 0) { LOGE("Unable to get software parameters: %s", snd_strerror(err)); goto done; } // Configure ALSA to start the transfer when the buffer is almost full. snd_pcm_get_params(handle->handle, &bufferSize, &periodSize); if (handle->devices & AudioSystem::DEVICE_OUT_ALL) { // For playback, configure ALSA to start the transfer when the // buffer is full. startThreshold = bufferSize - 1; stopThreshold = bufferSize; } else { // For recording, configure ALSA to start the transfer on the // first frame. startThreshold = 1; stopThreshold = bufferSize; } err = snd_pcm_sw_params_set_start_threshold(handle->handle, softwareParams, startThreshold); if (err < 0) { LOGE("Unable to set start threshold to %lu frames: %s", startThreshold, snd_strerror(err)); goto done; } err = snd_pcm_sw_params_set_stop_threshold(handle->handle, softwareParams, stopThreshold); if (err < 0) { LOGE("Unable to set stop threshold to %lu frames: %s", stopThreshold, snd_strerror(err)); goto done; } // Allow the transfer to start when at least periodSize samples can be // processed. err = snd_pcm_sw_params_set_avail_min(handle->handle, softwareParams, periodSize); if (err < 0) { LOGE("Unable to configure available minimum to %lu: %s", periodSize, snd_strerror(err)); goto done; } // Commit the software parameters back to the device. err = snd_pcm_sw_params(handle->handle, softwareParams); if (err < 0) LOGE("Unable to configure software parameters: %s", snd_strerror(err)); done: snd_pcm_sw_params_free(softwareParams); 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 alsa_set_params(snd_pcm_t *pcm_handle, int rw, int bits, int stereo, int rate) { snd_pcm_hw_params_t *hwparams=NULL; snd_pcm_sw_params_t *swparams=NULL; int dir; uint exact_uvalue; unsigned long exact_ulvalue; int channels; int periods=ALSA_PERIODS; int periodsize=ALSA_PERIOD_SIZE; int err; int format; /* Allocate the snd_pcm_hw_params_t structure on the stack. */ snd_pcm_hw_params_alloca(&hwparams); /* Init hwparams with full configuration space */ if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { ms_warning("alsa_set_params: Cannot configure this PCM device.\n"); return -1; } if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { ms_warning("alsa_set_params: Error setting access.\n"); return -1; } /* Set sample format */ format=SND_PCM_FORMAT_S16; if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) { ms_warning("alsa_set_params: Error setting format.\n"); return -1; } /* Set number of channels */ if (stereo) channels=2; else channels=1; if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) { ms_warning("alsa_set_params: Error setting channels.\n"); return -1; } /* Set sample rate. If the exact rate is not supported */ /* by the hardware, use nearest possible rate. */ exact_uvalue=rate; dir=0; if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_uvalue, &dir))<0){ ms_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err)); return -1; } if (dir != 0) { ms_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n " "==> Using %d Hz instead.\n", rate, exact_uvalue); } /* choose greater period size when rate is high */ periodsize=periodsize*(rate/8000); /* Set buffer size (in frames). The resulting latency is given by */ /* latency = periodsize * periods / (rate * bytes_per_frame) */ /* set period size */ exact_ulvalue=periodsize; dir=0; if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_ulvalue, &dir) < 0) { ms_warning("alsa_set_params: Error setting period size.\n"); return -1; } if (dir != 0) { ms_warning("alsa_set_params: The period size %d is not supported by your hardware.\n " "==> Using %d instead.\n", periodsize, (int)exact_ulvalue); } periodsize=exact_ulvalue; /* Set number of periods. Periods used to be called fragments. */ exact_uvalue=periods; dir=0; if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_uvalue, &dir) < 0) { ms_warning("alsa_set_params: Error setting periods.\n"); return -1; } if (dir != 0) { ms_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n " "==> Using %d instead.\n", periods, exact_uvalue); } /* Apply HW parameter settings to */ /* PCM device and prepare device */ if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { ms_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err)); return -1; } /*prepare sw params */ if (rw){ 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,periodsize*4 ))<0){ ms_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err)); } if ((err=snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams,periodsize*periods ))<0){ ms_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err)); } if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){ ms_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err)); return -1; } } return 0; }