static int quh_alsa_config (st_quh_nfo_t *file) { (void) file; #if 0 snd_pcm_hw_params_t *hw_params; snd_pcm_format_t format; int rate = 0; if (snd_pcm_hw_params_malloc (&hw_params) < 0) return -1; if (snd_pcm_hw_params_any (handle, hw_params) < 0) { snd_pcm_hw_params_free (hw_params); return -1; } if (snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { snd_pcm_hw_params_free (hw_params); return -1; } switch (file->size) { case 1: format = SND_PCM_FORMAT_S8; break; case 2: format = SND_PCM_FORMAT_S16; break; case 3: format = SND_PCM_FORMAT_S24; break; default: format = SND_PCM_FORMAT_S16; break; } if (snd_pcm_hw_params_set_format (handle, hw_params, format) < 0) { snd_pcm_hw_params_free (hw_params); return -1; } rate = file->rate; if (snd_pcm_hw_params_set_rate_near (handle, hw_params, rate, 0) < 0) { snd_pcm_hw_params_free (hw_params); return -1; } if ((float) rate * 1.05 < file->rate || (float) rate * 0.95 > file->rate) { snd_pcm_hw_params_free (hw_params); return -1; } if (snd_pcm_hw_params_set_channels (handle, hw_params, file->channels) < 0) { snd_pcm_hw_params_free (hw_params); return -1; } if (snd_pcm_hw_params (handle, hw_params) < 0) { snd_pcm_hw_params_free (hw_params); return -1; } snd_pcm_hw_params_free (hw_params); #endif return 0; }
void *capture_thread(void *data) { AudioCapture *capture = (AudioCapture *)data; // enif_keep_resource(capture); detect_pcm(capture); set_volume(capture, 100); snd_pcm_open(&capture->handle, capture->pcm_name, SND_PCM_STREAM_CAPTURE, 0); if(!capture->handle) { fprintf(stderr, "No PCM!!\r\n"); exit(1); } snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_malloc(&hw_params); if(!hw_params) { fprintf(stderr, "Damn!! No hw_params\r\n"); exit(1); } snd_pcm_hw_params_any(capture->handle, hw_params); snd_pcm_hw_params_set_access(capture->handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(capture->handle, hw_params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_rate_near(capture->handle, hw_params, &capture->sample_rate, 0); snd_pcm_hw_params_set_channels(capture->handle, hw_params, capture->channels); // int buffer_size = 16384; // int period_time = 32000; // int period_size = 1024; // snd_pcm_hw_params_set_period_time_near(capture->handle, hw_params, &period_time, 0); // snd_pcm_hw_params_set_period_size_near(capture->handle, hw_params, &period_size, 0); // snd_pcm_hw_params_set_buffer_size_near(capture->handle, hw_params, &buffer_size); // capture->last_dts = 0; fprintf(stderr, "Setting params: %p, %p\r\n", capture->handle, hw_params); snd_pcm_hw_params(capture->handle, hw_params); snd_pcm_hw_params_free(hw_params); snd_pcm_prepare(capture->handle); snd_output_t *log; snd_output_stdio_attach(&log, stderr, 0); snd_pcm_hw_params_dump(hw_params, log); fprintf(stderr, "Started capture\r\n"); char *buffer = (char *)malloc(8192); // char *ptr = buffer; int size = 0; while(capture->thread_started) { int r = snd_pcm_readi(capture->handle, buffer + size, 1024); size += r*2*capture->channels; if(size < capture->frame_size) { continue; } ErlNifEnv* env = enif_alloc_env(); ErlNifBinary frame; enif_alloc_binary(capture->frame_size, &frame); memmove(frame.data, buffer, frame.size); size -= frame.size; memmove(buffer, buffer + frame.size, size); ErlNifUInt64 dts = (uint64_t)capture->counter*1024ULL*1000 / capture->sample_rate; // fprintf(stderr, "A: %d -> %d\r\n", capture->counter, dts); if(capture->last_dts > dts) { fprintf(stderr, "Achtung! ALSA audio jump: %u, %u, %u\r\n", (unsigned)capture->counter, (unsigned)capture->last_dts, (unsigned)dts); } capture->last_dts = dts; enif_send(NULL, &capture->owner_pid, env, enif_make_tuple4(env, enif_make_atom(env, "alsa"), enif_make_resource(env, capture), enif_make_uint64(env, dts), enif_make_binary(env, &frame) ) ); enif_release_binary(&frame); enif_free_env(env); capture->counter++; } fprintf(stderr, "Capture thread stopping\r\n"); // enif_release_resource(capture); snd_pcm_close(capture->handle); return 0; }
static void *alsa_thread_init(const char *device, unsigned rate, unsigned latency) { snd_pcm_uframes_t buffer_size; snd_pcm_format_t format; snd_pcm_hw_params_t *params = NULL; snd_pcm_sw_params_t *sw_params = NULL; const char *alsa_dev = device ? device : "default"; unsigned latency_usec = latency * 1000 / 2; unsigned channels = 2; unsigned periods = 4; alsa_thread_t *alsa = (alsa_thread_t*) calloc(1, sizeof(alsa_thread_t)); if (!alsa) return NULL; TRY_ALSA(snd_pcm_open(&alsa->pcm, alsa_dev, SND_PCM_STREAM_PLAYBACK, 0)); TRY_ALSA(snd_pcm_hw_params_malloc(¶ms)); alsa->has_float = alsathread_find_float_format(alsa->pcm, params); format = alsa->has_float ? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16; TRY_ALSA(snd_pcm_hw_params_any(alsa->pcm, params)); TRY_ALSA(snd_pcm_hw_params_set_access( alsa->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED)); TRY_ALSA(snd_pcm_hw_params_set_format(alsa->pcm, params, format)); TRY_ALSA(snd_pcm_hw_params_set_channels(alsa->pcm, params, channels)); TRY_ALSA(snd_pcm_hw_params_set_rate(alsa->pcm, params, rate, 0)); TRY_ALSA(snd_pcm_hw_params_set_buffer_time_near( alsa->pcm, params, &latency_usec, NULL)); TRY_ALSA(snd_pcm_hw_params_set_periods_near( alsa->pcm, params, &periods, NULL)); TRY_ALSA(snd_pcm_hw_params(alsa->pcm, params)); /* Shouldn't have to bother with this, * but some drivers are apparently broken. */ if (snd_pcm_hw_params_get_period_size(params, &alsa->period_frames, NULL)) snd_pcm_hw_params_get_period_size_min( params, &alsa->period_frames, NULL); RARCH_LOG("ALSA: Period size: %d frames\n", (int)alsa->period_frames); if (snd_pcm_hw_params_get_buffer_size(params, &buffer_size)) snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size); RARCH_LOG("ALSA: Buffer size: %d frames\n", (int)buffer_size); alsa->buffer_size = snd_pcm_frames_to_bytes(alsa->pcm, buffer_size); alsa->period_size = snd_pcm_frames_to_bytes(alsa->pcm, alsa->period_frames); TRY_ALSA(snd_pcm_sw_params_malloc(&sw_params)); TRY_ALSA(snd_pcm_sw_params_current(alsa->pcm, sw_params)); TRY_ALSA(snd_pcm_sw_params_set_start_threshold( alsa->pcm, sw_params, buffer_size / 2)); TRY_ALSA(snd_pcm_sw_params(alsa->pcm, sw_params)); snd_pcm_hw_params_free(params); snd_pcm_sw_params_free(sw_params); alsa->fifo_lock = slock_new(); alsa->cond_lock = slock_new(); alsa->cond = scond_new(); alsa->buffer = fifo_new(alsa->buffer_size); if (!alsa->fifo_lock || !alsa->cond_lock || !alsa->cond || !alsa->buffer) goto error; alsa->worker_thread = sthread_create(alsa_worker_thread, alsa); if (!alsa->worker_thread) { RARCH_ERR("error initializing worker thread"); goto error; } return alsa; error: RARCH_ERR("ALSA: Failed to initialize...\n"); if (params) snd_pcm_hw_params_free(params); if (sw_params) snd_pcm_sw_params_free(sw_params); alsa_thread_free(alsa); return NULL; }
static void 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); } } }
static int set_hwparams (GstAlsaSink * alsa) { guint rrate; gint err; snd_pcm_hw_params_t *params; guint period_time, buffer_time; snd_pcm_hw_params_malloc (¶ms); GST_DEBUG_OBJECT (alsa, "Negotiating to %d channels @ %d Hz (format = %s) " "SPDIF (%d)", alsa->channels, alsa->rate, snd_pcm_format_name (alsa->format), alsa->iec958); /* start with requested values, if we cannot configure alsa for those values, * we set these values to -1, which will leave the default alsa values */ buffer_time = alsa->buffer_time; period_time = alsa->period_time; retry: /* choose all parameters */ CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config); /* set the interleaved read/write format */ CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access), wrong_access); /* set the sample format */ if (alsa->iec958) { /* Try to use big endian first else fallback to le and swap bytes */ if (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format) < 0) { alsa->format = SND_PCM_FORMAT_S16_LE; alsa->need_swap = TRUE; GST_DEBUG_OBJECT (alsa, "falling back to little endian with swapping"); } else { alsa->need_swap = FALSE; } } CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format), no_sample_format); /* set the count of channels */ CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels), no_channels); /* set the stream rate */ rrate = alsa->rate; CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL), no_rate); #ifndef GST_DISABLE_GST_DEBUG /* get and dump some limits */ { guint min, max; snd_pcm_hw_params_get_buffer_time_min (params, &min, NULL); snd_pcm_hw_params_get_buffer_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u", alsa->buffer_time, min, max); snd_pcm_hw_params_get_period_time_min (params, &min, NULL); snd_pcm_hw_params_get_period_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u", alsa->period_time, min, max); snd_pcm_hw_params_get_periods_min (params, &min, NULL); snd_pcm_hw_params_get_periods_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); } #endif /* now try to configure the buffer time and period time, if one * of those fail, we fall back to the defaults and emit a warning. */ if (buffer_time != -1 && !alsa->iec958) { /* set the buffer time */ if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, &buffer_time, NULL)) < 0) { GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set buffer time %i for playback: %s", buffer_time, snd_strerror (err))); /* disable buffer_time the next round */ buffer_time = -1; goto retry; } GST_DEBUG_OBJECT (alsa, "buffer time %u", buffer_time); } if (period_time != -1 && !alsa->iec958) { /* set the period time */ if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params, &period_time, NULL)) < 0) { GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set period time %i for playback: %s", period_time, snd_strerror (err))); /* disable period_time the next round */ period_time = -1; goto retry; } GST_DEBUG_OBJECT (alsa, "period time %u", period_time); } /* Set buffer size and period size manually for SPDIF */ if (G_UNLIKELY (alsa->iec958)) { snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE; snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE; CHECK (snd_pcm_hw_params_set_buffer_size_near (alsa->handle, params, &buffer_size), buffer_size); CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params, &period_size, NULL), period_size); } /* write the parameters to device */ CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); /* now get the configured values */ CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size), buffer_size); CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, NULL), period_size); GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size, alsa->period_size); snd_pcm_hw_params_free (params); return 0; /* ERRORS */ no_config: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Broken configuration for playback: no configurations available: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } wrong_access: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Access type not available for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_sample_format: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Sample format not available for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_channels: { gchar *msg = NULL; if ((alsa->channels) == 1) msg = g_strdup (_("Could not open device for playback in mono mode.")); if ((alsa->channels) == 2) msg = g_strdup (_("Could not open device for playback in stereo mode.")); if ((alsa->channels) > 2) msg = g_strdup_printf (_ ("Could not open device for playback in %d-channel mode."), alsa->channels); GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg), ("%s", snd_strerror (err))); g_free (msg); snd_pcm_hw_params_free (params); return err; } no_rate: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Rate %iHz not available for playback: %s", alsa->rate, snd_strerror (err))); return err; } buffer_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get buffer size for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } period_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get period size for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } set_hw_params: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set hw params for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } }
static GF_Err ALSA_ConfigureOutput(GF_AudioOutput*dr, u32 *SampleRate, u32 *NbChannels, u32 *nbBitsPerSample, u32 channel_cfg) { snd_pcm_hw_params_t *hw_params = NULL; int err; int nb_bufs, sr, val, period_time; ALSAContext *ctx = (ALSAContext*)dr->opaque; if (!ctx) return GF_BAD_PARAM; /*close device*/ if (ctx->playback_handle) { snd_pcm_close(ctx->playback_handle); ctx->playback_handle = NULL; } if (ctx->wav_buf) free(ctx->wav_buf); ctx->wav_buf = NULL; err = snd_pcm_open(&ctx->playback_handle, ctx->dev_name, SND_PCM_STREAM_PLAYBACK, 0/*SND_PCM_NONBLOCK*/); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot open audio device %s: %s\n", ctx->dev_name, snd_strerror (err)) ); return GF_IO_ERR; } err = snd_pcm_hw_params_malloc(&hw_params); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot allocate hardware params: %s\n", snd_strerror (err)) ); goto err_exit; } err = snd_pcm_hw_params_any(ctx->playback_handle, hw_params); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot initialize hardware params: %s\n", snd_strerror (err)) ); goto err_exit; } err = snd_pcm_hw_params_set_access(ctx->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set access type: %s\n", snd_strerror (err)) ); goto err_exit; } /*set output format*/ ctx->nb_ch = (int) (*NbChannels); ctx->block_align = ctx->nb_ch; if ((*nbBitsPerSample) == 16) { ctx->block_align *= 2; err = snd_pcm_hw_params_set_format(ctx->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE); } else { err = snd_pcm_hw_params_set_format(ctx->playback_handle, hw_params, SND_PCM_FORMAT_U8); } if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set sample format: %s\n", snd_strerror (err)) ); goto err_exit; } /*set output sample rate*/ if (ctx->force_sr) *SampleRate = ctx->force_sr; sr = *SampleRate; err = snd_pcm_hw_params_set_rate_near(ctx->playback_handle, hw_params, SampleRate, 0); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set sample rate: %s\n", snd_strerror (err)) ); goto err_exit; } if (sr != *SampleRate) { GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[ALSA] Sample rate %d not supported, using %d instead\n", sr, *SampleRate ) ); sr = *SampleRate; } /*set output channels*/ err = snd_pcm_hw_params_set_channels_near(ctx->playback_handle, hw_params, NbChannels); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set channel count: %s\n", snd_strerror (err)) ); goto err_exit; } if (ctx->nb_ch != *NbChannels) { GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[ALSA] %d channels not supported - using %d instead\n", ctx->nb_ch, *NbChannels ) ); ctx->block_align /= ctx->nb_ch; ctx->nb_ch = *NbChannels; ctx->block_align *= ctx->nb_ch; } err = snd_pcm_hw_params(ctx->playback_handle, hw_params); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set parameters: %s\n", snd_strerror (err)) ); goto err_exit; } /* Set number of buffers*/ snd_pcm_hw_params_get_periods_min(hw_params, &val, 0); nb_bufs = (ctx->num_buffers>val) ? ctx->num_buffers : val; err = snd_pcm_hw_params_set_periods_near(ctx->playback_handle, hw_params, &nb_bufs, 0); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set number of HW buffers (%d): %s\n", nb_bufs, snd_strerror(err) )); goto err_exit; } /* Set total buffer size*/ if (ctx->total_duration) { ctx->buf_size = (sr * ctx->total_duration)/1000; } else { ctx->buf_size = 2048; } ctx->buf_size /= nb_bufs; err = snd_pcm_hw_params_set_period_size_near(ctx->playback_handle, hw_params, (snd_pcm_uframes_t *)&ctx->buf_size, 0); if (err < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set HW buffer size (%d): %s\n", ctx->buf_size, snd_strerror(err) )); goto err_exit; } /*get complete buffer size*/ snd_pcm_hw_params_get_buffer_size(hw_params, (snd_pcm_uframes_t *)&ctx->buf_size); ctx->buf_size *= ctx->block_align; /*get period time*/ snd_pcm_hw_params_get_period_time(hw_params, &period_time, 0); snd_pcm_hw_params_free (hw_params); hw_params = NULL; ctx->delay = (ctx->buf_size*1000) / (sr*ctx->block_align); /*allocate a single buffer*/ ctx->wav_buf = malloc(ctx->buf_size*sizeof(char)); if(!ctx->wav_buf) return GF_OUT_OF_MEM; memset(ctx->wav_buf, 0, ctx->buf_size*sizeof(char)); GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[ALSA] Setup %d ch @ %d hz - %d periods of %d us - total buffer size %d - overall delay %d ms\n", ctx->nb_ch, sr, nb_bufs, period_time, ctx->buf_size, ctx->delay)); return GF_OK; err_exit: if (hw_params) snd_pcm_hw_params_free(hw_params); snd_pcm_close(ctx->playback_handle); ctx->playback_handle = NULL; return GF_IO_ERR; }
AudioSourceNix::~AudioSourceNix() { snd_pcm_hw_params_free(params); }
static snd_pcm_t * alsa_open (int channels, unsigned samplerate, int realtime) { const char * device = "default" ; snd_pcm_t *alsa_dev = NULL ; snd_pcm_hw_params_t *hw_params ; snd_pcm_uframes_t buffer_size ; snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ; snd_pcm_sw_params_t *sw_params ; int err ; if (realtime) { alsa_period_size = 256 ; alsa_buffer_frames = 3 * alsa_period_size ; } else { alsa_period_size = 1024 ; alsa_buffer_frames = 4 * alsa_period_size ; } ; if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ; goto catch_error ; } ; snd_pcm_nonblock (alsa_dev, 0) ; if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_hw_params_any (alsa_dev, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_hw_params_set_access (alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_hw_params_set_format (alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_hw_params_set_rate_near (alsa_dev, hw_params, &samplerate, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_hw_params_set_channels (alsa_dev, hw_params, channels)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_dev, hw_params, &alsa_buffer_frames)) < 0) { fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_hw_params_set_period_size_near (alsa_dev, hw_params, &alsa_period_size, 0)) < 0) { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_hw_params (alsa_dev, hw_params)) < 0) { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; /* extra check: if we have only one period, this code won't work */ snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ; snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ; if (alsa_period_size == buffer_size) { fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ; goto catch_error ; } ; snd_pcm_hw_params_free (hw_params) ; if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0) { fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_sw_params_current (alsa_dev, sw_params)) != 0) { fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ; goto catch_error ; } ; /* note: set start threshold to delay start until the ring buffer is full */ snd_pcm_sw_params_current (alsa_dev, sw_params) ; if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, buffer_size)) < 0) { fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ; goto catch_error ; } ; if ((err = snd_pcm_sw_params (alsa_dev, sw_params)) != 0) { fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ; goto catch_error ; } ; snd_pcm_sw_params_free (sw_params) ; snd_pcm_reset (alsa_dev) ; catch_error : if (err < 0 && alsa_dev != NULL) { snd_pcm_close (alsa_dev) ; return NULL ; } ; return alsa_dev ; } /* alsa_open */
int initAlsa(char **argv,int optind) { snd_pcm_hw_params_t *hw_params; int err,n; unsigned int Fs; if ((err = snd_pcm_open(&capture_handle, argv[optind], SND_PCM_STREAM_CAPTURE, 0)) < 0) { fprintf(stderr, "Alsa cannot open audio device %s (%s)\n",argv[optind], snd_strerror(err)); return 1; } if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { fprintf(stderr, "Alsa cannot allocate hardware parameter structure (%s)\n",snd_strerror(err)); return 1; } if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) { fprintf(stderr, "Alsa cannot initialize hardware parameter structure (%s)\n",snd_strerror(err)); return 1; } if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf(stderr, "Alsa cannot set access type (%s)\n",snd_strerror(err)); return 1; } if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params,SND_PCM_FORMAT_S16)) < 0) { fprintf(stderr, "Alsa cannot set sample format (%s)\n",snd_strerror(err)); return 1; } snd_pcm_hw_params_set_rate_resample(capture_handle, hw_params,0); Fs=19200; n=1; if ((err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &Fs,&n)) < 0) { fprintf(stderr, "Alsa cannot set sample rate (%s)\n",snd_strerror(err)); return 1; } fprintf(stderr, "Alsa sample rate %d\n",Fs); if(snd_pcm_hw_params_get_channels (hw_params, &nbch)!=0) { fprintf(stderr, "Alsa cannot get number of channels\n"); return 1; } if(nbch>4) { fprintf(stderr, "Alsa too much channels\n"); return 1; } if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) { fprintf(stderr, "Alsa cannot set parameters (%s)\n",snd_strerror(err)); return 1; } snd_pcm_hw_params_free(hw_params); if ((err = snd_pcm_prepare(capture_handle)) < 0) { fprintf(stderr, "Alsa cannot prepare audio interface for use (%s)\n",snd_strerror(err)); return 1; } for(n=0; n<nbch; n++) { channel[n].chn=n; channel[n].Infs=Fs; channel[n].InBuff=malloc(MAXNBFRAMES*sizeof(sample_t)); } for(; n<MAXNBCHANNELS; n++) channel[n].Infs=0; return (0); }
static RD_BOOL alsa_set_format(snd_pcm_t * pcm, RD_WAVEFORMATEX * pwfx) { snd_pcm_hw_params_t *hwparams = NULL; int err; unsigned int buffertime; short samplewidth; int audiochannels; unsigned int rate; samplewidth = pwfx->wBitsPerSample / 8; if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0) { error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0) { error("snd_pcm_hw_params_any: %s\n", snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err)); return False; } if (pwfx->wBitsPerSample == 16) { if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) { error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err)); return False; } } else { if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S8)) < 0) { error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err)); return False; } } #if 0 if ((err = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 1)) < 0) { error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err)); return False; } #endif rate = pwfx->nSamplesPerSec; if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0) { error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err)); return False; } audiochannels = pwfx->nChannels; if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams, pwfx->nChannels)) < 0) { error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err)); return False; } buffertime = 500000; /* microseconds */ if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams, &buffertime, 0)) < 0) { error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0) { error("snd_pcm_hw_params: %s\n", snd_strerror(err)); return False; } snd_pcm_hw_params_free(hwparams); if ((err = snd_pcm_prepare(pcm)) < 0) { error("snd_pcm_prepare: %s\n", snd_strerror(err)); return False; } reopened = True; return True; }
/************************************************************************** * widOpen [internal] */ static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) { WINE_WAVEDEV* wwi; snd_pcm_hw_params_t * hw_params; snd_pcm_sw_params_t * sw_params; snd_pcm_access_t access; snd_pcm_format_t format; unsigned int rate; unsigned int buffer_time = 500000; unsigned int period_time = 10000; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; int flags; snd_pcm_t * pcm; int err; int dir; DWORD ret; /* JPW TODO - review this code */ TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { WARN("Invalid Parameter !\n"); return MMSYSERR_INVALPARAM; } if (wDevID >= ALSA_WidNumDevs) { TRACE("Requested device %d, but only %d are known!\n", wDevID, ALSA_WidNumDevs); return MMSYSERR_BADDEVICEID; } /* only PCM format is supported so far... */ if (!ALSA_supportedFormat(lpDesc->lpFormat)) { WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n", lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels, lpDesc->lpFormat->nSamplesPerSec); return WAVERR_BADFORMAT; } if (dwFlags & WAVE_FORMAT_QUERY) { TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n", lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels, lpDesc->lpFormat->nSamplesPerSec); return MMSYSERR_NOERROR; } wwi = &WInDev[wDevID]; if (wwi->pcm != NULL) { WARN("already allocated\n"); return MMSYSERR_ALLOCATED; } wwi->pcm = 0; flags = SND_PCM_NONBLOCK; if ( (err=snd_pcm_open(&pcm, wwi->pcmname, SND_PCM_STREAM_CAPTURE, flags)) < 0 ) { ERR("Error open: %s\n", snd_strerror(err)); return MMSYSERR_NOTENABLED; } wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); wwi->waveDesc = *lpDesc; ALSA_copyFormat(lpDesc->lpFormat, &wwi->format); if (wwi->format.Format.wBitsPerSample == 0) { WARN("Resetting zeroed wBitsPerSample\n"); wwi->format.Format.wBitsPerSample = 8 * (wwi->format.Format.nAvgBytesPerSec / wwi->format.Format.nSamplesPerSec) / wwi->format.Format.nChannels; } hw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof() ); sw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof() ); snd_pcm_hw_params_any(pcm, hw_params); #define EXIT_ON_ERROR(f,e,txt) do \ { \ int err; \ if ( (err = (f) ) < 0) \ { \ WARN(txt ": %s\n", snd_strerror(err)); \ ret = (e); \ goto error; \ } \ } while(0) access = SND_PCM_ACCESS_MMAP_INTERLEAVED; if ( ( err = snd_pcm_hw_params_set_access(pcm, hw_params, access ) ) < 0) { WARN("mmap not available. switching to standard write.\n"); access = SND_PCM_ACCESS_RW_INTERLEAVED; EXIT_ON_ERROR( snd_pcm_hw_params_set_access(pcm, hw_params, access ), MMSYSERR_INVALPARAM, "unable to set access for playback"); wwi->read = snd_pcm_readi; } else wwi->read = snd_pcm_mmap_readi; EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwi->format.Format.nChannels), WAVERR_BADFORMAT, "unable to set required channels"); if ((wwi->format.Format.wFormatTag == WAVE_FORMAT_PCM) || ((wwi->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) && IsEqualGUID(&wwi->format.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) { format = (wwi->format.Format.wBitsPerSample == 8) ? SND_PCM_FORMAT_U8 : (wwi->format.Format.wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE : (wwi->format.Format.wBitsPerSample == 24) ? SND_PCM_FORMAT_S24_3LE : (wwi->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_S32_LE : -1; } else if ((wwi->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) && IsEqualGUID(&wwi->format.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){ format = (wwi->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_FLOAT_LE : -1; } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_MULAW) { FIXME("unimplemented format: WAVE_FORMAT_MULAW\n"); ret = WAVERR_BADFORMAT; goto error; } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_ALAW) { FIXME("unimplemented format: WAVE_FORMAT_ALAW\n"); ret = WAVERR_BADFORMAT; goto error; } else if (wwi->format.Format.wFormatTag == WAVE_FORMAT_ADPCM) { FIXME("unimplemented format: WAVE_FORMAT_ADPCM\n"); ret = WAVERR_BADFORMAT; goto error; } else { ERR("invalid format: %0x04x\n", wwi->format.Format.wFormatTag); ret = WAVERR_BADFORMAT; goto error; } EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), WAVERR_BADFORMAT, "unable to set required format"); rate = wwi->format.Format.nSamplesPerSec; dir = 0; err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, &dir); if (err < 0) { WARN("Rate %d Hz not available for playback: %s\n", wwi->format.Format.nSamplesPerSec, snd_strerror(rate)); ret = WAVERR_BADFORMAT; goto error; } if (!ALSA_NearMatch(rate, wwi->format.Format.nSamplesPerSec)) { WARN("Rate doesn't match (requested %d Hz, got %d Hz)\n", wwi->format.Format.nSamplesPerSec, rate); ret = WAVERR_BADFORMAT; goto error; } dir=0; EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, &dir), MMSYSERR_INVALPARAM, "unable to set buffer time"); dir=0; EXIT_ON_ERROR( snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &period_time, &dir), MMSYSERR_INVALPARAM, "unable to set period time"); EXIT_ON_ERROR( snd_pcm_hw_params(pcm, hw_params), MMSYSERR_INVALPARAM, "unable to set hw params for playback"); dir=0; err = snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir); err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size); snd_pcm_sw_params_current(pcm, sw_params); EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set start threshold"); EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size"); EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min"); EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold"); EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback"); #undef EXIT_ON_ERROR snd_pcm_prepare(pcm); if (TRACE_ON(wave)) ALSA_TraceParameters(hw_params, sw_params, FALSE); /* now, we can save all required data for later use... */ if ( wwi->hw_params ) snd_pcm_hw_params_free(wwi->hw_params); snd_pcm_hw_params_malloc(&(wwi->hw_params)); snd_pcm_hw_params_copy(wwi->hw_params, hw_params); wwi->dwBufferSize = snd_pcm_frames_to_bytes(pcm, buffer_size); wwi->lpQueuePtr = wwi->lpPlayPtr = wwi->lpLoopPtr = NULL; wwi->pcm = pcm; ALSA_InitRingMessage(&wwi->msgRing); wwi->dwPeriodSize = snd_pcm_frames_to_bytes(pcm, period_size); TRACE("dwPeriodSize=%u\n", wwi->dwPeriodSize); TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n", wwi->format.Format.wBitsPerSample, wwi->format.Format.nAvgBytesPerSec, wwi->format.Format.nSamplesPerSec, wwi->format.Format.nChannels, wwi->format.Format.nBlockAlign); wwi->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL); wwi->hThread = CreateThread(NULL, 0, widRecorder, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwi->dwThreadID)); if (wwi->hThread) SetThreadPriority(wwi->hThread, THREAD_PRIORITY_TIME_CRITICAL); WaitForSingleObject(wwi->hStartUpEvent, INFINITE); CloseHandle(wwi->hStartUpEvent); wwi->hStartUpEvent = INVALID_HANDLE_VALUE; HeapFree( GetProcessHeap(), 0, hw_params ); HeapFree( GetProcessHeap(), 0, sw_params ); return widNotifyClient(wwi, WIM_OPEN, 0L, 0L); error: snd_pcm_close(pcm); HeapFree( GetProcessHeap(), 0, hw_params ); HeapFree( GetProcessHeap(), 0, sw_params ); return ret; }
// alsa main (int argc, char *argv[]) { int i; int err; short buf[128]; snd_pcm_t *playback_handle; snd_pcm_hw_params_t *hw_params; 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_prepare (playback_handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); exit (1); } for (i = 0; i < 10; ++i) { if ((err = snd_pcm_writei (playback_handle, buf, 128)) != 128) { fprintf (stderr, "write to audio interface failed (%s)\n", snd_strerror (err)); exit (1); } } snd_pcm_close (playback_handle); exit (0); }
static ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName) { const char *driver = NULL; snd_pcm_hw_params_t *hp; snd_pcm_uframes_t bufferSizeInFrames; snd_pcm_uframes_t periodSizeInFrames; ALboolean needring = AL_FALSE; snd_pcm_format_t format; const char *funcerr; alsa_data *data; int err; if(deviceName) { size_t idx; if(!allCaptureDevNameMap) allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); for(idx = 0;idx < numCaptureDevNames;idx++) { if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0) { driver = allCaptureDevNameMap[idx].device; break; } } if(idx == numCaptureDevNames) return ALC_INVALID_VALUE; } else { deviceName = alsaDevice; driver = GetConfigValue("alsa", "capture", "default"); } data = (alsa_data*)calloc(1, sizeof(alsa_data)); err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if(err < 0) { ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); free(data); return ALC_INVALID_VALUE; } format = -1; switch(Device->FmtType) { case DevFmtByte: format = SND_PCM_FORMAT_S8; break; case DevFmtUByte: format = SND_PCM_FORMAT_U8; break; case DevFmtShort: format = SND_PCM_FORMAT_S16; break; case DevFmtUShort: format = SND_PCM_FORMAT_U16; break; case DevFmtInt: format = SND_PCM_FORMAT_S32; break; case DevFmtUInt: format = SND_PCM_FORMAT_U32; break; case DevFmtFloat: format = SND_PCM_FORMAT_FLOAT; break; } funcerr = NULL; bufferSizeInFrames = maxu(Device->UpdateSize*Device->NumUpdates, 100*Device->Frequency/1000); periodSizeInFrames = minu(bufferSizeInFrames, 25*Device->Frequency/1000); snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp)); /* set interleaved access */ CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); /* set format (implicitly sets sample bits) */ CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format)); /* set channels (implicitly sets frame bits) */ CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(Device->FmtChans))); /* set rate (implicitly constrains period/buffer parameters) */ CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, Device->Frequency, 0)); /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0) { TRACE("Buffer too large, using intermediate ring buffer\n"); needring = AL_TRUE; CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames)); } /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL)); /* install and prepare hardware configuration */ CHECK(snd_pcm_hw_params(data->pcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); #undef CHECK snd_pcm_hw_params_free(hp); hp = NULL; if(needring) { data->ring = CreateRingBuffer(FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType), Device->UpdateSize*Device->NumUpdates); if(!data->ring) { ERR("ring buffer create failed\n"); goto error2; } data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames); data->buffer = malloc(data->size); if(!data->buffer) { ERR("buffer malloc failed\n"); goto error2; } } Device->DeviceName = strdup(deviceName); Device->ExtraData = data; return ALC_NO_ERROR; error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); error2: free(data->buffer); DestroyRingBuffer(data->ring); snd_pcm_close(data->pcmHandle); free(data); Device->ExtraData = NULL; return ALC_INVALID_VALUE; }
static ALCboolean alsa_reset_playback(ALCdevice *device) { alsa_data *data = (alsa_data*)device->ExtraData; snd_pcm_uframes_t periodSizeInFrames; unsigned int periodLen, bufferLen; snd_pcm_sw_params_t *sp = NULL; snd_pcm_hw_params_t *hp = NULL; snd_pcm_access_t access; snd_pcm_format_t format; unsigned int periods; unsigned int rate; const char *funcerr; int allowmmap; int err; format = -1; switch(device->FmtType) { case DevFmtByte: format = SND_PCM_FORMAT_S8; break; case DevFmtUByte: format = SND_PCM_FORMAT_U8; break; case DevFmtShort: format = SND_PCM_FORMAT_S16; break; case DevFmtUShort: format = SND_PCM_FORMAT_U16; break; case DevFmtInt: format = SND_PCM_FORMAT_S32; break; case DevFmtUInt: format = SND_PCM_FORMAT_U32; break; case DevFmtFloat: format = SND_PCM_FORMAT_FLOAT; break; } allowmmap = GetConfigValueBool("alsa", "mmap", 1); periods = device->NumUpdates; periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; bufferLen = periodLen * periods; rate = device->Frequency; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp)); /* set interleaved access */ if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { if(periods > 2) { periods--; bufferLen = periodLen * periods; } CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); } /* test and set format (implicitly sets sample bits) */ if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0) { static const struct { snd_pcm_format_t format; enum DevFmtType fmttype; } formatlist[] = { { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, { SND_PCM_FORMAT_S32, DevFmtInt }, { SND_PCM_FORMAT_U32, DevFmtUInt }, { SND_PCM_FORMAT_S16, DevFmtShort }, { SND_PCM_FORMAT_U16, DevFmtUShort }, { SND_PCM_FORMAT_S8, DevFmtByte }, { SND_PCM_FORMAT_U8, DevFmtUByte }, }; size_t k; for(k = 0;k < COUNTOF(formatlist);k++) { format = formatlist[k].format; if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0) { device->FmtType = formatlist[k].fmttype; break; } } } CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format)); /* test and set channels (implicitly sets frame bits) */ if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0) { static const enum DevFmtChannels channellist[] = { DevFmtStereo, DevFmtQuad, DevFmtX51, DevFmtX71, DevFmtMono, }; size_t k; for(k = 0;k < COUNTOF(channellist);k++) { if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0) { device->FmtChans = channellist[k]; break; } } } CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); /* set rate (implicitly constrains period/buffer parameters) */ if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL)); /* set buffer time (implicitly constrains period/buffer parameters) */ CHECK(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL)); /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ CHECK(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL)); /* install and prepare hardware configuration */ CHECK(snd_pcm_hw_params(data->pcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL)); snd_pcm_hw_params_free(hp); hp = NULL; snd_pcm_sw_params_malloc(&sp); CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp)); CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)); CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods)); CHECK(snd_pcm_sw_params(data->pcmHandle, sp)); #undef CHECK snd_pcm_sw_params_free(sp); sp = NULL; /* Increase periods by one, since the temp buffer counts as an extra * period */ if(access == SND_PCM_ACCESS_RW_INTERLEAVED) device->NumUpdates = periods+1; else device->NumUpdates = periods; device->UpdateSize = periodSizeInFrames; device->Frequency = rate; SetDefaultChannelOrder(device); return ALC_TRUE; error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); if(sp) snd_pcm_sw_params_free(sp); return ALC_FALSE; }
AudioCaptureNode::~AudioCaptureNode() { if(buffer) delete buffer; snd_pcm_hw_params_free(hwParams); snd_pcm_close(captureHandle); }
static void init_audio(const char* devname) { snd_pcm_hw_params_t* hwparams = 0; snd_pcm_sw_params_t* swparams = 0; snd_pcm_uframes_t bufsize = 0; unsigned int buftime = 1000000; unsigned int pertime = 50000; int dir = 0; int rc; if ((rc = snd_output_stdio_attach(&output, stderr, 0)) < 0) exit_snd_error(rc, "log output"); if ((rc = snd_pcm_open(&audio, devname, SND_PCM_STREAM_PLAYBACK, 0)) < 0) exit_snd_error(rc, "opening device"); if ((rc = snd_pcm_hw_params_malloc(&hwparams)) < 0) exit_snd_error(rc, "hardware parameters"); if ((rc = snd_pcm_hw_params_any(audio, hwparams)) < 0) exit_snd_error(rc, "hardware parameters"); if ((rc = snd_pcm_hw_params_set_rate_resample(audio, hwparams, 0)) < 0) exit_snd_error(rc, "hardware parameters"); if ((rc = snd_pcm_hw_params_set_access(audio, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) exit_snd_error(rc, "access type"); if ((rc = snd_pcm_hw_params_set_format(audio, hwparams, SND_PCM_FORMAT_S16)) < 0) exit_snd_error(rc, "sample format"); if ((rc = snd_pcm_hw_params_set_channels_near(audio, hwparams, &n_channels)) < 0) exit_snd_error(rc, "number of channels"); if ((rc = snd_pcm_hw_params_set_rate_near(audio, hwparams, &samplerate, &dir)) < 0) exit_snd_error(rc, "sample rate"); if ((rc = snd_pcm_hw_params_set_buffer_time_near(audio, hwparams, &buftime, &dir)) < 0) exit_snd_error(rc, "buffer time"); if ((rc = snd_pcm_hw_params_set_period_time_near(audio, hwparams, &pertime, &dir)) < 0) exit_snd_error(rc, "period time"); if ((rc = snd_pcm_hw_params(audio, hwparams)) < 0) exit_snd_error(rc, "applying hardware parameters"); if ((rc = snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize)) < 0) exit_snd_error(rc, "buffer size"); if ((rc = snd_pcm_hw_params_get_period_size(hwparams, &periodsize, &dir)) < 0) exit_snd_error(rc, "period size"); snd_pcm_hw_params_free(hwparams); if ((rc = snd_pcm_sw_params_malloc(&swparams)) < 0) exit_snd_error(rc, "software parameters"); if ((rc = snd_pcm_sw_params_current(audio, swparams)) < 0) exit_snd_error(rc, "software parameters"); if ((rc = snd_pcm_sw_params_set_start_threshold(audio, swparams, bufsize / periodsize * periodsize)) < 0) exit_snd_error(rc, "start threshold"); if ((rc = snd_pcm_sw_params(audio, swparams)) < 0) exit_snd_error(rc, "applying software parameters"); snd_pcm_sw_params_free(swparams); if ((rc = snd_pcm_prepare(audio)) < 0) exit_snd_error(rc, "preparing device"); }
av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, unsigned int *sample_rate, int channels, enum AVCodecID *codec_id) { AlsaData *s = ctx->priv_data; const char *audio_device; int res, flags = 0; snd_pcm_format_t format; snd_pcm_t *h; snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t buffer_size, period_size; uint64_t layout = ctx->streams[0]->codecpar->channel_layout; if (ctx->filename[0] == 0) audio_device = "default"; else audio_device = ctx->filename; if (*codec_id == AV_CODEC_ID_NONE) *codec_id = DEFAULT_CODEC_ID; format = codec_id_to_pcm_format(*codec_id); if (format == SND_PCM_FORMAT_UNKNOWN) { av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id); return AVERROR(ENOSYS); } s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels; if (ctx->flags & AVFMT_FLAG_NONBLOCK) { flags = SND_PCM_NONBLOCK; } res = snd_pcm_open(&h, audio_device, mode, flags); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot open audio device %s (%s)\n", audio_device, snd_strerror(res)); return AVERROR(EIO); } res = snd_pcm_hw_params_malloc(&hw_params); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot allocate hardware parameter structure (%s)\n", snd_strerror(res)); goto fail1; } res = snd_pcm_hw_params_any(h, hw_params); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot initialize hardware parameter structure (%s)\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_access(h, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set access type (%s)\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_format(h, hw_params, format); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set sample format 0x%04x %d (%s)\n", *codec_id, format, snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_rate_near(h, hw_params, sample_rate, 0); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set sample rate (%s)\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_channels(h, hw_params, channels); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n", channels, snd_strerror(res)); goto fail; } snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size); buffer_size = FFMIN(buffer_size, ALSA_BUFFER_SIZE_MAX); /* TODO: maybe use ctx->max_picture_buffer somehow */ res = snd_pcm_hw_params_set_buffer_size_near(h, hw_params, &buffer_size); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set ALSA buffer size (%s)\n", snd_strerror(res)); goto fail; } snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, NULL); if (!period_size) period_size = buffer_size / 4; res = snd_pcm_hw_params_set_period_size_near(h, hw_params, &period_size, NULL); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set ALSA period size (%s)\n", snd_strerror(res)); goto fail; } s->period_size = period_size; res = snd_pcm_hw_params(h, hw_params); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set parameters (%s)\n", snd_strerror(res)); goto fail; } snd_pcm_hw_params_free(hw_params); if (channels > 2 && layout) { if (find_reorder_func(s, *codec_id, layout, mode == SND_PCM_STREAM_PLAYBACK) < 0) { char name[128]; av_get_channel_layout_string(name, sizeof(name), channels, layout); av_log(ctx, AV_LOG_WARNING, "ALSA channel layout unknown or unimplemented for %s %s.\n", name, mode == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture"); } if (s->reorder_func) { s->reorder_buf_size = buffer_size; s->reorder_buf = av_malloc(s->reorder_buf_size * s->frame_size); if (!s->reorder_buf) goto fail1; } } s->h = h; return 0; fail: snd_pcm_hw_params_free(hw_params); fail1: snd_pcm_close(h); return AVERROR(EIO); }
av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, unsigned int *sample_rate, int channels, enum CodecID *codec_id) { AlsaData *s = ctx->priv_data; const char *audio_device; int res, flags = 0; snd_pcm_format_t format; snd_pcm_t *h; snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t buffer_size, period_size; if (ctx->filename[0] == 0) audio_device = "default"; else audio_device = ctx->filename; if (*codec_id == CODEC_ID_NONE) *codec_id = DEFAULT_CODEC_ID; format = codec_id_to_pcm_format(*codec_id); if (format == SND_PCM_FORMAT_UNKNOWN) { av_log(ctx, AV_LOG_ERROR, "sample format 0x%04x is not supported\n", *codec_id); return AVERROR(ENOSYS); } s->frame_size = av_get_bits_per_sample(*codec_id) / 8 * channels; if (ctx->flags & AVFMT_FLAG_NONBLOCK) { flags = SND_PCM_NONBLOCK; } res = snd_pcm_open(&h, audio_device, mode, flags); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot open audio device %s (%s)\n", audio_device, snd_strerror(res)); return AVERROR_IO; } res = snd_pcm_hw_params_malloc(&hw_params); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot allocate hardware parameter structure (%s)\n", snd_strerror(res)); goto fail1; } res = snd_pcm_hw_params_any(h, hw_params); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot initialize hardware parameter structure (%s)\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_access(h, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set access type (%s)\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_format(h, hw_params, format); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set sample format 0x%04x %d (%s)\n", *codec_id, format, snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_rate_near(h, hw_params, sample_rate, 0); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set sample rate (%s)\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_channels(h, hw_params, channels); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set channel count to %d (%s)\n", channels, snd_strerror(res)); goto fail; } snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size); /* TODO: maybe use ctx->max_picture_buffer somehow */ res = snd_pcm_hw_params_set_buffer_size_near(h, hw_params, &buffer_size); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set ALSA buffer size (%s)\n", snd_strerror(res)); goto fail; } snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, NULL); res = snd_pcm_hw_params_set_period_size_near(h, hw_params, &period_size, NULL); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set ALSA period size (%s)\n", snd_strerror(res)); goto fail; } s->period_size = period_size; res = snd_pcm_hw_params(h, hw_params); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "cannot set parameters (%s)\n", snd_strerror(res)); goto fail; } snd_pcm_hw_params_free(hw_params); s->h = h; return 0; fail: snd_pcm_hw_params_free(hw_params); fail1: snd_pcm_close(h); return AVERROR_IO; }
static void *_msynth_thread_main(void *arg) { int i; int err; int sample; int processed; struct sampleclock sc = {0, 0, 0.0f, 0.0f}; msynth_frame fb = NULL; puts("synthread: started"); /* Begin initialization of ALSA */ /* snd_pcm_open(pcm_handle, device_name, stream_type, open_mode) */ err = snd_pcm_open(&pcm, config.device_name, SND_PCM_STREAM_PLAYBACK, 0); ALSERT("opening audio device"); /* First ALSA hardware settings */ /* Allocate HW params */ err = snd_pcm_hw_params_malloc(&hw_p); ALSERT("allocating hw params"); /* Get default HW parameters */ err = snd_pcm_hw_params_any(pcm, hw_p); ALSERT("requesting hw default params"); /* Disable software resampling */ err = snd_pcm_hw_params_set_rate_resample(pcm, hw_p, config.resample); ALSERT("disabling software resampling"); /* Configure sample rate */ if (config.srate != -1) srate = config.srate; else { /* Get maximum hardware samplerate */ err = snd_pcm_hw_params_get_rate_max(hw_p, &srate, &dir); ALSERT("requesting maximum hardware samplerate"); } /* Set sample rate * snd_pcm_hw_params_set_rate_near(pcn, hw_p, *rate, * 0 (== set exact rate)) */ err = snd_pcm_hw_params_set_rate_near(pcm, hw_p, &srate, 0); ALSERT("setting samplerate"); printf("synthread: Detected samplerate of %u\n", srate); /* RW interleaved access (means we will use the snd_pcm_writei function) */ err = snd_pcm_hw_params_set_access(pcm, hw_p, SND_PCM_ACCESS_RW_INTERLEAVED); ALSERT("setting access mode"); /* native-endian 16-bit signed sample format */ err = snd_pcm_hw_params_set_format(pcm, hw_p, SND_PCM_FORMAT_S16); ALSERT("setting sample format"); /* Switch to 2.0ch audio */ err = snd_pcm_hw_params_set_channels(pcm, hw_p, 2); ALSERT("switching to 2.0ch audio"); if (config.buffer_time != -1) { /* Set configured buffer time */ err = snd_pcm_hw_params_set_buffer_time_near(pcm, hw_p, &config.buffer_time, &dir); ALSERT("setting buffer time"); /* Fetch resulting size */ err = snd_pcm_hw_params_get_buffer_size(hw_p, &buffer_size); ALSERT("getting buffer size"); } else { /* Since we want the interactive synthesizer to be very responsive * select a minimum buffer size. */ err = snd_pcm_hw_params_set_buffer_size_first(pcm, hw_p, &buffer_size); ALSERT("setting buffer size"); } printf("synthread: Selected buffersize of %lu\n", buffer_size); printf("synthread: Response delay is approximately %.2f ms\n", (double)buffer_size / (double)srate * 1000.0); if (config.period_time != -1) { err = snd_pcm_hw_params_set_period_time_near(pcm, hw_p, &config.period_time, &dir); ALSERT("setting period time"); err = snd_pcm_hw_params_get_period_size(hw_p, &period_size, &dir); ALSERT("getting period size"); } else { /* Select a period time of half the buffer time * since this improves processing performance */ err = snd_pcm_hw_params_set_period_size_last(pcm, hw_p, &period_size, &dir); ALSERT("setting period size"); } if (dir) printf("synthread: Selected period size near %lu\n", period_size); else printf("synthread: Selected period size of %lu\n", period_size); /* write hw parameters to device */ err = snd_pcm_hw_params(pcm, hw_p); ALSERT("writing hw params"); /* Begin ALSA software side setup */ /* Allocate SW params */ err = snd_pcm_sw_params_malloc(&sw_p); ALSERT("allocating sw params"); /* Request software current settings */ err = snd_pcm_sw_params_current(pcm, sw_p); ALSERT("requesting current sw params"); /* Automatically start playing after the first period is written */ err = snd_pcm_sw_params_set_start_threshold(pcm, sw_p, period_size); ALSERT("settings start threshold"); /* XRUN when buffer is empty */ err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_p, buffer_size * 2); ALSERT("setting stop threshold"); /* Block synthesizer when there is not at least period frames available */ err = snd_pcm_sw_params_set_avail_min(pcm, sw_p, period_size); ALSERT("setting minimum free frames"); /* Write software parameters */ err = snd_pcm_sw_params(pcm, sw_p); ALSERT("writing sw params"); printf("synthread: Audio system configured.\n"); /* Prepare device for playback */ err = snd_pcm_prepare(pcm); ALSERT("preparing device"); /* Allocate a period sized framebuffer * (yup an audio buffer is in ALSA speak indeed called a framebuffer) */ fb = malloc(sizeof(struct _msynth_frame) * period_size); if (!fb) { perror("malloc framebuffer failed"); exit(1); } /* Set sampleclock to 0 */ sc.samples = 0; sc.samplerate = srate; sc.cycle = 0.0f; sc.seconds = 0.0f; /* Initially the <root> variable describing the flow of sound within * the synthesizer is configured to be a NULL signal. (silence) */ /* Signal successful completion of initialization */ pthread_mutex_lock(&mutex); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); /* -------------- Main loop --------------- */ while (!shutdown) { /* Only during generation we need the synth tree to be static */ synth_lock_graphs(); for (i = 0; i < period_size; i++) { /* Evaluate variables */ ssv_eval(sc); sample = (int)(32767.5 * ssv_get_var_eval("left") * volume); /* Clip samples */ if (sample > 32767) sample = 32767; if (sample < -32768) sample = -32768; fb[i].left = (short)sample; sample = (int)(32767.5 * ssv_get_var_eval("right") * volume); /* Clip samples */ if (sample > 32767) sample = 32767; if (sample < -32768) sample = -32768; fb[i].right = (short)sample; sc = sc_from_samples(sc.samplerate, sc.samples + 1); } synth_unlock_graphs(); /* Send audio to sound card */ processed = 0; while (processed != period_size) { err = snd_pcm_writei(pcm, fb + processed, period_size - processed); /* Retry on interruption by signal */ if (err == -EAGAIN) continue; /* Recover from XRUN/suspend */ if (err < 0) { err = synth_recover(err); ALSERT("sending audio"); continue; } /* Update processed samples */ processed += err; } } puts("synthread: shutting down"); /* Dump any statistics recorded */ if (recover_resumes) printf("synthread: Device was resumed %i times\n", recover_resumes); if (recover_xruns) printf("synthread: %i xrun recoveries were needed\n", recover_xruns); printf("synthread: processed %i samples\n", sc.samples); /* Wait for playback to complete */ err = snd_pcm_drain(pcm); ALSERT("draining device"); /* Shutdown PCM device */ err = snd_pcm_close(pcm); ALSERT("closing audio device"); /* Clean up parameters */ snd_pcm_hw_params_free(hw_p); snd_pcm_sw_params_free(sw_p); return NULL; }
snd_pcm_t * setup_alsa_capture() { snd_pcm_t *capture_handle; snd_pcm_hw_params_t *hw_params; int err; char *device = DEFAULT_DEVICE; uint32_t rate = RATE; uint32_t channels = CHANNELS; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; if ((err = snd_pcm_open (&capture_handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) { fatal_tragedy(1, "cannot open audio device %s (%s)", device, snd_strerror (err)); } log_info("audio interface opened"); if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fatal_tragedy(1 , "cannot allocate hardware parameter structure (%s)", snd_strerror (err)); } log_info("hw_params allocated"); if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) { fatal_tragedy(1, "cannot initialize hardware parameter structure (%s)", snd_strerror (err)); } log_info("hw_params initialized"); if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fatal_tragedy(1, "cannot set access type (%s)", snd_strerror (err)); } log_info("hw_params access setted"); if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, format)) < 0) { fatal_tragedy(1, "cannot set sample format (%s)", snd_strerror (err)); } fprintf(stdout, "hw_params format setted"); if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &rate, 0)) < 0) { fatal_tragedy(1, "cannot set sample rate (%s)", snd_strerror (err)); } log_info("hw_params rate setted"); if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, channels)) < 0) { fatal_tragedy(1, "cannot set channel count (%s)", snd_strerror (err)); } log_info("hw_params channels setted"); if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) { fatal_tragedy(1, "cannot set parameters (%s)", snd_strerror (err)); } fprintf(stdout, "hw_params setted"); snd_pcm_hw_params_free (hw_params); if ((err = snd_pcm_prepare (capture_handle)) < 0) { fatal_tragedy(1, "cannot prepare audio interface for use (%s)", snd_strerror (err)); } log_info("audio interface prepared"); return capture_handle; }
static snd_pcm_t *alsa_open(snd_pcm_t **pcm_handle, int stream_type, snd_pcm_uframes_t *buffer_size) { char *pcm_name = "chumix"; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; unsigned int buffer_time; int status; snd_pcm_uframes_t xfer_align; // Open the device. Experimenting with duplex mode. fprintf(stderr, "Opening PCM device\n"); status = snd_pcm_open(pcm_handle, pcm_name, stream_type, 0); if(status < 0) { fprintf(stderr, "Unable to open audio device: %s\n", snd_strerror(status)); goto error; } // Determine what the hardware can do. fprintf(stderr, "Allocating hw params\n"); snd_pcm_hw_params_malloc(&hwparams); status = snd_pcm_hw_params_any(*pcm_handle, hwparams); if(status < 0) { fprintf(stderr, "Unable to get hardware parameters: %s\n", snd_strerror(status)); goto error; } // Set up interleaved audio. fprintf(stderr, "Setting up interleaved audio\n"); status = snd_pcm_hw_params_set_access(*pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if(status < 0) { fprintf(stderr, "Unable to set interleaved mode: %s\n", snd_strerror(status)); goto error; } // Set the audio format. fprintf(stderr, "Setting format\n"); status = snd_pcm_hw_params_set_format(*pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE); if(status<0) { fprintf(stderr, "Unable to set audio format: %s\n", snd_strerror(status)); goto error; } // Set stereo audio. fprintf(stderr, "Setting channels\n"); status = snd_pcm_hw_params_set_channels(*pcm_handle, hwparams, 2); if(status<0) { fprintf(stderr, "Unable to set stereo mode: %s\n", snd_strerror(status)); goto error; } // Set sample rate. fprintf(stderr, "Setting audio rate\n"); int rate = 44100; status = snd_pcm_hw_params_set_rate_near(*pcm_handle, hwparams, &rate, NULL); if(status<0) { fprintf(stderr, "Unable to set sample rate to 44100: %s\n", snd_strerror(status)); goto error; } // Set buffer time to a reasonable value. // Probably won't work for playback, as it's fixed in /etc/asound.conf buffer_time = BUFFER_TIME; status = snd_pcm_hw_params_set_buffer_time_near(*pcm_handle, hwparams, &buffer_time, 0); snd_pcm_hw_params_get_buffer_size(hwparams, buffer_size); // Write the settings out to the audio card. fprintf(stderr, "Setting hw params\n"); status = snd_pcm_hw_params(*pcm_handle, hwparams); if(status<0) { fprintf(stderr, "Unable to set audio parameters: %s\n", snd_strerror(status)); goto error; } snd_pcm_hw_params_free(hwparams); status = snd_pcm_prepare(*pcm_handle); if(status<0) { fprintf(stderr, "Unable to prepare audio device: %s\n", snd_strerror(status)); goto error; } return *pcm_handle; error: if(*pcm_handle) { snd_pcm_drain(*pcm_handle); snd_pcm_close(*pcm_handle); } return NULL; }
/*------------------------------------------------------------------------------ * Open the audio source *----------------------------------------------------------------------------*/ bool AlsaDspSource :: open ( void ) throw ( Exception ) { unsigned int u; snd_pcm_format_t format; snd_pcm_hw_params_t *hwParams; if ( isOpen() ) { return false; } switch ( getBitsPerSample() ) { case 8: format = SND_PCM_FORMAT_S8; break; case 16: format = SND_PCM_FORMAT_S16; break; default: return false; } if (snd_pcm_open(&captureHandle, pcmName, SND_PCM_STREAM_CAPTURE, 0) < 0) { captureHandle = 0; return false; } if (snd_pcm_hw_params_malloc(&hwParams) < 0) { close(); throw Exception( __FILE__, __LINE__, "can't alloc hardware "\ "parameter structure"); } if (snd_pcm_hw_params_any(captureHandle, hwParams) < 0) { snd_pcm_hw_params_free(hwParams); close(); throw Exception( __FILE__, __LINE__, "can't initialize hardware "\ "parameter structure"); } if (snd_pcm_hw_params_set_access(captureHandle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { snd_pcm_hw_params_free(hwParams); close(); throw Exception( __FILE__, __LINE__, "can't set access type"); } if (snd_pcm_hw_params_set_format(captureHandle, hwParams, format) < 0) { snd_pcm_hw_params_free(hwParams); close(); throw Exception( __FILE__, __LINE__, "can't set sample format"); } u = getSampleRate(); if (snd_pcm_hw_params_set_rate_near(captureHandle, hwParams, &u, 0) < 0) { snd_pcm_hw_params_free(hwParams); close(); throw Exception( __FILE__, __LINE__, "can't set sample rate", u); } u = getChannel(); if (snd_pcm_hw_params_set_channels(captureHandle, hwParams, u) < 0) { snd_pcm_hw_params_free(hwParams); close(); throw Exception( __FILE__, __LINE__, "can't set channels", u); } u = 4; if (snd_pcm_hw_params_set_periods_near(captureHandle, hwParams, &u, 0) < 0) { snd_pcm_hw_params_free(hwParams); close(); throw Exception( __FILE__, __LINE__, "can't set interrupt frequency"); } u = getBufferTime(); if (snd_pcm_hw_params_set_buffer_time_near(captureHandle, hwParams, &u, 0) < 0) { snd_pcm_hw_params_free(hwParams); close(); throw Exception( __FILE__, __LINE__, "can't set buffer size"); } if (snd_pcm_hw_params(captureHandle, hwParams) < 0) { snd_pcm_hw_params_free(hwParams); close(); throw Exception( __FILE__, __LINE__, "can't set hardware parameters"); } snd_pcm_hw_params_free(hwParams); if (snd_pcm_prepare(captureHandle) < 0) { close(); throw Exception( __FILE__, __LINE__, "can't prepare audio interface "\ "for use"); } bytesPerFrame = getChannel() * getBitsPerSample() / 8; return true; }
short *Audio_ALSA::open (AudioConfig &cfg, const char *) { AudioConfig tmpCfg; if (_audioHandle != NULL) { _errorString = "ERROR: Device already in use"; return NULL; } snd_pcm_uframes_t buffer_frames; snd_pcm_hw_params_t *hw_params = 0; if (snd_pcm_open (&_audioHandle, "default", SND_PCM_STREAM_PLAYBACK, 0)) { _errorString = "ERROR: Could not open audio device."; goto open_error; } // May later be replaced with driver defaults. tmpCfg = cfg; if (snd_pcm_hw_params_malloc (&hw_params)) { _errorString = "ERROR: could not malloc hwparams."; goto open_error; } if (snd_pcm_hw_params_any (_audioHandle, hw_params)) { _errorString = "ERROR: could not initialize hw params"; goto open_error; } if (snd_pcm_hw_params_set_access (_audioHandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) { _errorString = "ERROR: could not set access type"; goto open_error; } if (snd_pcm_hw_params_set_format (_audioHandle, hw_params, SND_PCM_FORMAT_S16_LE)) { _errorString = "ERROR: could not set sample format"; goto open_error; } if (snd_pcm_hw_params_set_channels (_audioHandle, hw_params, tmpCfg.channels)) { _errorString = "ERROR: could not set channel count"; goto open_error; } { // Gentoo bug #98769, comment 4 unsigned int rate = tmpCfg.frequency; if (snd_pcm_hw_params_set_rate_near (_audioHandle, hw_params, &rate, 0)) { _errorString = "ERROR: could not set sample rate"; goto open_error; } } _alsa_to_frames_divisor = tmpCfg.channels; buffer_frames = 4096; snd_pcm_hw_params_set_period_size_near(_audioHandle, hw_params, &buffer_frames, 0); if (snd_pcm_hw_params (_audioHandle, hw_params)) { _errorString = "ERROR: could not set hw parameters"; goto open_error; } snd_pcm_hw_params_free (hw_params); hw_params = 0; if (snd_pcm_prepare (_audioHandle)) { _errorString = "ERROR: could not prepare audio interface for use"; goto open_error; } tmpCfg.bufSize = buffer_frames * _alsa_to_frames_divisor; #ifdef HAVE_EXCEPTIONS _sampleBuffer = new(std::nothrow) short[tmpCfg.bufSize]; #else _sampleBuffer = new short[tmpCfg.bufSize]; #endif if (!_sampleBuffer) { _errorString = "AUDIO: Unable to allocate memory for sample buffers."; goto open_error; } // Setup internal Config _settings = tmpCfg; // Update the users settings getConfig (cfg); return _sampleBuffer; open_error: if (hw_params) snd_pcm_hw_params_free (hw_params); if (_audioHandle != NULL) close (); perror ("ALSA"); return NULL; }
int main(int argc, char** argv) { snd_pcm_t *handle = NULL; snd_pcm_hw_params_t *params = NULL; snd_pcm_uframes_t frames = 64; int dir = 0, size, loops; unsigned int val; int ret = 0, n = 0; unsigned char *buf = NULL; FILE *fpcm = NULL; unsigned int rate; int format; int channel; int time; /* int i; for(i = 0; i < argc; i++) AUDIO_ALSA_DBG("param%d: %s\n", i, *(argv + i)); */ if(7 != argc) { AUDIO_ALSA_DBG("\n"); AUDIO_ALSA_DBG("param1 snd dev: alsa device name: default, plughw:0,0 or plughw:1,0\n"); AUDIO_ALSA_DBG("param2 filename: file used to save audio pcm data\n"); AUDIO_ALSA_DBG("param3 sampleRate: 8000 -- 48000 \n"); AUDIO_ALSA_DBG("param4 channel: 1:mono, 2:stereo\n"); AUDIO_ALSA_DBG("param5 format: 1:SND_PCM_FORMAT_U8, 2:SND_PCM_FORMAT_S16_LE\n"); AUDIO_ALSA_DBG("param6 record time: record time(unit: second)\n\n"); return -1; } rate = strtoul(*(argv + 3), NULL, 10); channel = strtoul(*(argv + 4), NULL, 10); format = strtoul(*(argv + 5), NULL, 10); time = strtoul(*(argv + 6), NULL, 10); if(rate < 8000 || rate > 48000) { AUDIO_ALSA_DBG("param2 sampleRate error: 8000 -- 48000 \n"); ret = -1; goto error; } if(channel < 1 || channel > 2) { AUDIO_ALSA_DBG("param3 channel error: 1:mono, 2:stereo\n"); ret = -1; goto error; } if(format < SND_PCM_FORMAT_U8 || format > SND_PCM_FORMAT_S16_LE) { AUDIO_ALSA_DBG("param4 format error: 1:SND_PCM_FORMAT_U8, 2:SND_PCM_FORMAT_S16_LE\n"); ret = -1; goto error; } AUDIO_ALSA_DBG("rate = %u channel = %s format = %s time = %d\n", rate, (1 == channel) ? "mono" : "stereo", (1 == format) ? "SND_PCM_FORMAT_U8" : "SND_PCM_FORMAT_S16_LE", time); if((ret = snd_pcm_open(&handle, *(argv + 1), SND_PCM_STREAM_CAPTURE, 0)) < 0) { AUDIO_ALSA_DBG("snd_pcm_open error: %s\n", snd_strerror(ret)); handle = NULL; goto error; } snd_pcm_hw_params_malloc(¶ms); if(!params) { AUDIO_ALSA_DBG("snd_pcm_hw_params_alloca error ... \n"); ret = -1; goto error; } snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if((ret = snd_pcm_hw_params_set_format(handle ,params, format)) < 0) { AUDIO_ALSA_DBG("format set error: %s\n", snd_strerror(ret)); goto error; } if((ret = snd_pcm_hw_params_set_channels(handle, params, channel)) < 0) { AUDIO_ALSA_DBG("channel set error: %s\n", snd_strerror(ret)); goto error; } if((ret = snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir)) < 0) { AUDIO_ALSA_DBG("sampleRate set error: %s\n", snd_strerror(ret)); goto error; } snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); if((ret = snd_pcm_hw_params(handle, params)) < 0) { AUDIO_ALSA_DBG("snd_pcm_hw_params error: %s\n", snd_strerror(ret)); goto error; } snd_pcm_hw_params_get_period_size(params, &frames, &dir); size = frames * channel * format; buf = (unsigned char*)malloc(size); if(!buf) { AUDIO_ALSA_DBG("malloc buf error: buf size = %d\n", size); ret = -1; goto error; } snd_pcm_hw_params_get_period_time(params, &val, &dir); loops = time * 1000000 / val; AUDIO_ALSA_DBG("loops = %d\n", loops); fpcm = fopen(*(argv + 2), "wb"); if(!fpcm) { AUDIO_ALSA_DBG("Can not open file %s ... \n", *(argv + 2)); goto error; } while(loops-- > 0) { n = snd_pcm_readi(handle, buf, frames); if(-EPIPE == n) { AUDIO_ALSA_DBG("snd_pcm_readi over run ... \n"); snd_pcm_prepare(handle); continue; } else if(n < 0) { AUDIO_ALSA_DBG("snd_pcm_readi error: %s\n", snd_strerror(n)); ret = -1; break; } else if(n != frames) { AUDIO_ALSA_DBG("snd_pcm_readi read frames %d, less than %u\n", n, (unsigned int)frames); } fwrite(buf, 1, size, fpcm); } error: if(params) snd_pcm_hw_params_free(params); if(handle) snd_pcm_close(handle); if(buf) free(buf); if(fpcm) fclose(fpcm); return ret; }
void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { snd_pcm_t* handle; snd_pcm_format_mask_t* formatMask; snd_pcm_format_t format; snd_pcm_hw_params_t* hwParams; int handledBits[MAX_BIT_INDEX+1]; int ret; int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc; int origSampleSizeInBytes, origSignificantBits; int channels, minChannels, maxChannels; int rate, bitIndex; for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE; if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) { return; } ret = snd_pcm_format_mask_malloc(&formatMask); if (ret != 0) { ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret); } else { ret = snd_pcm_hw_params_malloc(&hwParams); if (ret != 0) { ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); } else { ret = snd_pcm_hw_params_any(handle, hwParams); if (ret != 0) { ERROR1("snd_pcm_hw_params_any returned error %d\n", ret); } } snd_pcm_hw_params_get_format_mask(hwParams, formatMask); #ifdef ALSA_PCM_NEW_HW_PARAMS_API if (ret == 0) { ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels); if (ret != 0) { ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret); } } if (ret == 0) { ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels); if (ret != 0) { ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret); } } #else minChannels = snd_pcm_hw_params_get_channels_min(hwParams); maxChannels = snd_pcm_hw_params_get_channels_max(hwParams); if (minChannels > maxChannels) { ERROR2("MinChannels=%d, maxChannels=%d\n", minChannels, maxChannels); } #endif // since we queried the hw: device, for many soundcards, it will only // report the maximum number of channels (which is the only way to talk // to the hw: device). Since we will, however, open the plughw: device // when opening the Source/TargetDataLine, we can safely assume that // also the channels 1..maxChannels are available. #ifdef ALSA_PCM_USE_PLUGHW minChannels = 1; #endif if (ret == 0) { // plughw: supports any sample rate rate = -1; for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { if (snd_pcm_format_mask_test(formatMask, format)) { // format exists if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes, &origSignificantBits, &isSigned, &isBigEndian, &enc)) { // now if we use plughw:, we can use any bit size below the // natively supported ones. Some ALSA drivers only support the maximum // bit size, so we add any sample rates below the reported one. // E.g. this iteration reports support for 16-bit. // getBitIndex will return 2, so it will add entries for // 16-bit (bitIndex=2) and in the next do-while loop iteration, // it will decrease bitIndex and will therefore add 8-bit support. bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits); do { if (bitIndex == 0 || bitIndex == MAX_BIT_INDEX || !handledBits[bitIndex]) { handledBits[bitIndex] = TRUE; sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes); significantBits = getSignificantBits(bitIndex, origSignificantBits); if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) { // avoid too many channels explicitly listed // just add -1, min, and max DAUDIO_AddAudioFormat(creator, significantBits, -1, -1, rate, enc, isSigned, isBigEndian); DAUDIO_AddAudioFormat(creator, significantBits, sampleSizeInBytes * minChannels, minChannels, rate, enc, isSigned, isBigEndian); DAUDIO_AddAudioFormat(creator, significantBits, sampleSizeInBytes * maxChannels, maxChannels, rate, enc, isSigned, isBigEndian); } else { for (channels = minChannels; channels <= maxChannels; channels++) { DAUDIO_AddAudioFormat(creator, significantBits, (channels < 0)?-1:(sampleSizeInBytes * channels), channels, rate, enc, isSigned, isBigEndian); } } } #ifndef ALSA_PCM_USE_PLUGHW // without plugin, do not add fake formats break; #endif } while (--bitIndex > 0); } else { TRACE1("could not get format from alsa for format %d\n", format); } } else { //TRACE1("Format %d not supported\n", format); } } // for loop snd_pcm_hw_params_free(hwParams); } snd_pcm_format_mask_free(formatMask); } snd_pcm_close(handle); }
static void OpenAlsa() { int i; int err; short buf[128]; snd_pcm_t *capture_handle; snd_pcm_hw_params_t *hw_params; int card=0; int dev=0; if ((err = snd_pcm_open (&capture_handle, argv[1], SND_PCM_STREAM_CAPTURE, 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 (capture_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 (capture_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 (capture_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 (capture_handle, hw_params, FMT_dwSamplesPerSec, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, 2)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params (capture_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_prepare (capture_handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); exit (1); } for (i = 0; i < 10; ++i) { if ((err = snd_pcm_readi (capture_handle, buf, 128)) != 128) { fprintf (stderr, "read from audio interface failed (%s)\n", snd_strerror (err)); exit (1); } } snd_pcm_close (capture_handle); exit (0); }
eBool tfAlsa::openDevice(const eChar *device, eU32 freq, eU32 bits, eU32 channels) { eInt err = 0; if (device == eNULL) return eFALSE; printf ("opening device '%s' for playback\n", device); if ((err = snd_pcm_open (&m_handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf (stderr, "cannot open audio device '%s' for playback(%s)\n", device, snd_strerror (err)); return eFALSE; } snd_pcm_hw_params_t *hw_params; snd_pcm_format_t format; snd_pcm_uframes_t buffer_size = BUFFERSIZE; snd_pcm_uframes_t period_size = PERIODSIZE; printf("setting device to %i hz %i bits %i channels\n", freq, bits, channels); if (bits == 16) format = SND_PCM_FORMAT_S16_LE; else format = SND_PCM_FORMAT_S8; if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); return false; } if ((err = snd_pcm_hw_params_any (m_handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); return false; } if ((err = snd_pcm_hw_params_set_access (m_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); return false; } if ((err = snd_pcm_hw_params_set_format (m_handle, hw_params, format)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); return false; } if ((err = snd_pcm_hw_params_set_rate_near (m_handle, hw_params, (unsigned int *)&freq, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); return false; } if ((err = snd_pcm_hw_params_set_channels (m_handle, hw_params, channels)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); return false; } if ((err = snd_pcm_hw_params_set_buffer_size_near (m_handle, hw_params, &buffer_size)) < 0) { fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)); return false; } if ((err = snd_pcm_hw_params_set_period_size_near (m_handle, hw_params, &period_size, NULL)) < 0) { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)); return false; } if ((err = snd_pcm_hw_params (m_handle, hw_params)) < 0) { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)); return false; } snd_pcm_hw_params_free (hw_params); return eTRUE; }
static int palsa_set_hw_params (ddb_waveformat_t *fmt) { snd_pcm_hw_params_t *hw_params = NULL; int err = 0; memcpy (&plugin.fmt, fmt, sizeof (ddb_waveformat_t)); if (!plugin.fmt.channels) { // generic format plugin.fmt.bps = 16; plugin.fmt.is_float = 0; plugin.fmt.channels = 2; plugin.fmt.samplerate = 44100; plugin.fmt.channelmask = 3; } snd_pcm_nonblock(audio, 0); snd_pcm_drain (audio); snd_pcm_nonblock(audio, 1); if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); goto error; } if ((err = snd_pcm_hw_params_any (audio, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); goto error; } if ((err = snd_pcm_hw_params_set_access (audio, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); goto error; } snd_pcm_format_t sample_fmt; switch (plugin.fmt.bps) { case 8: sample_fmt = SND_PCM_FORMAT_S8; break; case 16: #if WORDS_BIGENDIAN sample_fmt = SND_PCM_FORMAT_S16_BE; #else sample_fmt = SND_PCM_FORMAT_S16_LE; #endif break; case 24: #if WORDS_BIGENDIAN sample_fmt = SND_PCM_FORMAT_S24_3BE; #else sample_fmt = SND_PCM_FORMAT_S24_3LE; #endif break; case 32: if (plugin.fmt.is_float) { #if WORDS_BIGENDIAN sample_fmt = SND_PCM_FORMAT_FLOAT_BE; #else sample_fmt = SND_PCM_FORMAT_FLOAT_LE; #endif } else { #if WORDS_BIGENDIAN sample_fmt = SND_PCM_FORMAT_S32_BE; #else sample_fmt = SND_PCM_FORMAT_S32_LE; #endif } break; } if ((err = snd_pcm_hw_params_set_format (audio, hw_params, sample_fmt)) < 0) { fprintf (stderr, "cannot set sample format to %d bps (error: %s), trying all supported formats\n", plugin.fmt.bps, snd_strerror (err)); int fmt_cnt[] = { 16, 24, 32, 32, 8 }; #if WORDS_BIGENDIAN int fmt[] = { SND_PCM_FORMAT_S16_BE, SND_PCM_FORMAT_S24_3BE, SND_PCM_FORMAT_S32_BE, SND_PCM_FORMAT_FLOAT_BE, SND_PCM_FORMAT_S8, -1 }; #else int fmt[] = { SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_FLOAT_LE, SND_PCM_FORMAT_S8, -1 }; #endif // 1st try formats with higher bps int i = 0; for (i = 0; fmt[i] != -1; i++) { if (fmt[i] != sample_fmt && fmt_cnt[i] > plugin.fmt.bps) { if (snd_pcm_hw_params_set_format (audio, hw_params, fmt[i]) >= 0) { fprintf (stderr, "Found compatible format %d bps\n", fmt_cnt[i]); sample_fmt = fmt[i]; break; } } } if (fmt[i] == -1) { // next try formats with lower bps i = 0; for (i = 0; fmt[i] != -1; i++) { if (fmt[i] != sample_fmt && fmt_cnt[i] < plugin.fmt.bps) { if (snd_pcm_hw_params_set_format (audio, hw_params, fmt[i]) >= 0) { fprintf (stderr, "Found compatible format %d bps\n", fmt_cnt[i]); sample_fmt = fmt[i]; break; } } } } if (fmt[i] == -1) { fprintf (stderr, "Fallback format could not be found\n"); goto error; } } snd_pcm_hw_params_get_format (hw_params, &sample_fmt); trace ("chosen sample format: %04Xh\n", (int)sample_fmt); int val = plugin.fmt.samplerate; int ret = 0; if ((err = snd_pcm_hw_params_set_rate_resample (audio, hw_params, conf_alsa_resample)) < 0) { fprintf (stderr, "cannot setup resampling (%s)\n", snd_strerror (err)); goto error; } if ((err = snd_pcm_hw_params_set_rate_near (audio, hw_params, &val, &ret)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); goto error; } plugin.fmt.samplerate = val; trace ("chosen samplerate: %d Hz\n", val); int chanmin, chanmax; snd_pcm_hw_params_get_channels_min (hw_params, &chanmin); snd_pcm_hw_params_get_channels_max (hw_params, &chanmax); trace ("minchan: %d, maxchan: %d\n", chanmin, chanmax); int nchan = plugin.fmt.channels; if (nchan > chanmax) { nchan = chanmax; } else if (nchan < chanmin) { nchan = chanmin; } trace ("setting chan=%d\n", nchan); if ((err = snd_pcm_hw_params_set_channels (audio, hw_params, nchan)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); } snd_pcm_hw_params_get_channels (hw_params, &nchan); trace ("alsa channels: %d\n", nchan); req_buffer_size = deadbeef->conf_get_int ("alsa.buffer", DEFAULT_BUFFER_SIZE); req_period_size = deadbeef->conf_get_int ("alsa.period", DEFAULT_PERIOD_SIZE); buffer_size = req_buffer_size; period_size = req_period_size; trace ("trying buffer size: %d frames\n", (int)buffer_size); trace ("trying period size: %d frames\n", (int)period_size); snd_pcm_hw_params_set_buffer_size_near (audio, hw_params, &buffer_size); snd_pcm_hw_params_set_period_size_near (audio, hw_params, &period_size, NULL); trace ("alsa buffer size: %d frames\n", (int)buffer_size); trace ("alsa period size: %d frames\n", (int)period_size); if ((err = snd_pcm_hw_params (audio, hw_params)) < 0) { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)); goto error; } plugin.fmt.is_float = 0; switch (sample_fmt) { case SND_PCM_FORMAT_S8: plugin.fmt.bps = 8; break; case SND_PCM_FORMAT_S16_BE: case SND_PCM_FORMAT_S16_LE: plugin.fmt.bps = 16; break; case SND_PCM_FORMAT_S24_3BE: case SND_PCM_FORMAT_S24_3LE: plugin.fmt.bps = 24; break; case SND_PCM_FORMAT_S32_BE: case SND_PCM_FORMAT_S32_LE: plugin.fmt.bps = 32; break; case SND_PCM_FORMAT_FLOAT_LE: case SND_PCM_FORMAT_FLOAT_BE: plugin.fmt.bps = 32; plugin.fmt.is_float = 1; break; } trace ("chosen bps: %d (%s)\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int"); plugin.fmt.channels = nchan; plugin.fmt.channelmask = 0; if (nchan == 1) { plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT; } if (nchan == 2) { plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT; } if (nchan == 3) { plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_LOW_FREQUENCY; } if (nchan == 4) { plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT; } if (nchan == 5) { plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER; } if (nchan == 6) { plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_LOW_FREQUENCY; } if (nchan == 7) { plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_SIDE_LEFT | DDB_SPEAKER_SIDE_RIGHT; } if (nchan == 8) { plugin.fmt.channelmask = DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT | DDB_SPEAKER_BACK_LEFT | DDB_SPEAKER_BACK_RIGHT | DDB_SPEAKER_FRONT_CENTER | DDB_SPEAKER_SIDE_LEFT | DDB_SPEAKER_SIDE_RIGHT | DDB_SPEAKER_LOW_FREQUENCY; } error: if (err < 0) { memset (&plugin.fmt, 0, sizeof (ddb_waveformat_t)); } if (hw_params) { snd_pcm_hw_params_free (hw_params); } return err; }
static snd_pcm_t * bg_alsa_open(const char * card, gavl_audio_format_t * format, snd_pcm_stream_t stream, gavl_time_t buffer_time, int * convert_4_3) { unsigned int i_tmp; int dir, err; snd_pcm_hw_params_t *hw_params = NULL; // snd_pcm_sw_params_t *sw_params = NULL; snd_pcm_t *ret = NULL; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; snd_pcm_uframes_t period_size_min = 0; snd_pcm_uframes_t period_size_max = 0; snd_pcm_uframes_t buffer_size_min = 0; snd_pcm_uframes_t buffer_size_max = 0; /* We open in non blocking mode so our process won't hang if the card is busy */ if((err = snd_pcm_open(&ret, card, stream, // SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_CAPTURE SND_PCM_NONBLOCK // SND_PCM_ASYNC ) < 0)) { ret = NULL; bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_open failed for device %s (%s)", card, snd_strerror(err)); goto fail; } /* Now, set blocking mode */ snd_pcm_nonblock(ret, 0); if(snd_pcm_hw_params_malloc(&hw_params) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_malloc failed"); goto fail; } if(snd_pcm_hw_params_any(ret, hw_params) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_any failed"); goto fail; } /* Interleave mode */ if(snd_pcm_hw_params_set_access(ret, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_access failed"); goto fail; } else format->interleave_mode = GAVL_INTERLEAVE_ALL; /* Sample format */ switch(format->sample_format) { case GAVL_SAMPLE_S8: case GAVL_SAMPLE_U8: if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S8) < 0) // if(1) { /* Soundcard support no 8-bit, try 16 */ if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S16) < 0) { /* Hopeless */ bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_format failed"); goto fail; } else format->sample_format = GAVL_SAMPLE_S16; } else format->sample_format = GAVL_SAMPLE_S8; break; case GAVL_SAMPLE_S16: case GAVL_SAMPLE_U16: if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S16) < 0) { /* Hopeless */ bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_format failed"); goto fail; } else format->sample_format = GAVL_SAMPLE_S16; break; case GAVL_SAMPLE_S32: #ifndef WORDS_BIGENDIAN if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S32_LE) < 0) #else if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S32_BE) < 0) #endif { /* Soundcard supports no 32-bit, try 24 (more probably supported but needs conversion) */ #ifndef WORDS_BIGENDIAN if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S24_3LE) < 0) #else if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S24_3BE) < 0) #endif { /* No 24 bit, try 16 */ if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S16) < 0) { /* Hopeless */ bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_format failed"); goto fail; } else format->sample_format = GAVL_SAMPLE_S16; } else { format->sample_format = GAVL_SAMPLE_S32; if(convert_4_3) *convert_4_3 = 1; } } else format->sample_format = GAVL_SAMPLE_S32; break; case GAVL_SAMPLE_FLOAT: case GAVL_SAMPLE_DOUBLE: if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_FLOAT) < 0) { #ifndef WORDS_BIGENDIAN if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S32_LE) < 0) #else if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S32_BE) < 0) #endif { /* Soundcard supports no 32-bit, try 24 (more probably supported but needs conversion) */ #ifndef WORDS_BIGENDIAN if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S24_3LE) < 0) #else if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S24_3BE) < 0) #endif { /* No 24 bit, try 16 */ if(snd_pcm_hw_params_set_format(ret, hw_params, SND_PCM_FORMAT_S16) < 0) { /* Hopeless */ bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_format failed"); goto fail; } else format->sample_format = GAVL_SAMPLE_S16; } else { format->sample_format = GAVL_SAMPLE_S32; if(convert_4_3) *convert_4_3 = 1; } } else format->sample_format = GAVL_SAMPLE_S32; } else format->sample_format = GAVL_SAMPLE_FLOAT; break; case GAVL_SAMPLE_NONE: goto fail; break; } /* Channels */ if(snd_pcm_hw_params_set_channels(ret, hw_params, format->num_channels) < 0) { if(format->num_channels == 1) /* Mono doesn't work, try stereo */ { if(snd_pcm_hw_params_set_channels(ret, hw_params, 2) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_channels failed (Format has %d channels)", format->num_channels); goto fail; } else { format->num_channels = 2; format->channel_locations[0] = GAVL_CHID_FRONT_LEFT; format->channel_locations[1] = GAVL_CHID_FRONT_RIGHT; } } else { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_channels failed (Format has %d channels)", format->num_channels); goto fail; } } /* Switch off driver side resampling */ #if SND_LIB_VERSION >= 0x010009 snd_pcm_hw_params_set_rate_resample(ret, hw_params, 0); #endif /* Samplerate */ i_tmp = format->samplerate; if(snd_pcm_hw_params_set_rate_near(ret, hw_params, &i_tmp, 0) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_rate_near failed"); goto fail; } if(format->samplerate != i_tmp) { bg_log(BG_LOG_INFO, LOG_DOMAIN, "Samplerate %d not supported by device %s, using %d", format->samplerate, card, i_tmp); } format->samplerate = i_tmp; dir = 0; /* Buffer size */ snd_pcm_hw_params_get_buffer_size_min(hw_params, &buffer_size_min); snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size_max); dir=0; snd_pcm_hw_params_get_period_size_min(hw_params, &period_size_min,&dir); dir=0; snd_pcm_hw_params_get_period_size_max(hw_params, &period_size_max,&dir); buffer_size = gavl_time_to_samples(format->samplerate, buffer_time); if(buffer_size > buffer_size_max) buffer_size = buffer_size_max; if(buffer_size < buffer_size_min) buffer_size = buffer_size_min; period_size = buffer_size / 8; buffer_size = period_size * 8; dir = 0; if(snd_pcm_hw_params_set_period_size_near(ret, hw_params, &period_size, &dir) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_period_size failed"); goto fail; } dir = 0; snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir); dir = 0; if(snd_pcm_hw_params_set_buffer_size_near(ret, hw_params, &buffer_size) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params_set_buffer_size failed"); goto fail; } snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size); format->samples_per_frame = period_size; /* Write params to card */ if(snd_pcm_hw_params (ret, hw_params) < 0) { bg_log(BG_LOG_ERROR, LOG_DOMAIN, "snd_pcm_hw_params failed"); goto fail; } snd_pcm_hw_params_free(hw_params); gavl_set_channel_setup(format); // gavl_audio_format_dump(format); return ret; fail: bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Alsa initialization failed"); if(ret) snd_pcm_close(ret); if(hw_params) snd_pcm_hw_params_free(hw_params); return NULL; }
static int laudio_alsa_open(void) { snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t bufsize; int ret; hw_params = NULL; ret = snd_pcm_open(&hdl, card_name, SND_PCM_STREAM_PLAYBACK, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not open playback device: %s\n", snd_strerror(ret)); return -1; } /* HW params */ ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not allocate hw params: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_any(hdl, hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not retrieve hw params: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_access(hdl, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set access method: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_format(hdl, hw_params, SND_PCM_FORMAT_S16_LE); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set S16LE format: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_channels(hdl, hw_params, 2); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set stereo output: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_rate(hdl, hw_params, 44100, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Hardware doesn't support 44.1 kHz: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufsize); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not get max buffer size: %s\n", snd_strerror(ret)); goto out_fail; } DPRINTF(E_DBG, L_LAUDIO, "Max buffer size is %lu samples\n", bufsize); ret = snd_pcm_hw_params_set_buffer_size_max(hdl, hw_params, &bufsize); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set buffer size to max: %s\n", snd_strerror(ret)); goto out_fail; } DPRINTF(E_DBG, L_LAUDIO, "Buffer size is %lu samples\n", bufsize); ret = snd_pcm_hw_params(hdl, hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set hw params: %s\n", snd_strerror(ret)); goto out_fail; } snd_pcm_hw_params_free(hw_params); hw_params = NULL; pcm_pos = 0; pcm_last_error = 0; pcm_recovery = 0; pcm_buf_threshold = (bufsize / AIRTUNES_V2_PACKET_SAMPLES) * AIRTUNES_V2_PACKET_SAMPLES; ret = mixer_open(); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not open mixer\n"); goto out_fail; } update_status(LAUDIO_OPEN); return 0; out_fail: if (hw_params) snd_pcm_hw_params_free(hw_params); snd_pcm_close(hdl); hdl = NULL; return -1; }