static int alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, cubeb_stream_params stream_params, unsigned int latency, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) { cubeb_stream * stm; int r; snd_pcm_format_t format; assert(ctx && stream); *stream = NULL; switch (stream_params.format) { case CUBEB_SAMPLE_S16LE: format = SND_PCM_FORMAT_S16_LE; break; case CUBEB_SAMPLE_S16BE: format = SND_PCM_FORMAT_S16_BE; break; case CUBEB_SAMPLE_FLOAT32LE: format = SND_PCM_FORMAT_FLOAT_LE; break; case CUBEB_SAMPLE_FLOAT32BE: format = SND_PCM_FORMAT_FLOAT_BE; break; default: return CUBEB_ERROR_INVALID_FORMAT; } pthread_mutex_lock(&ctx->mutex); if (ctx->active_streams >= CUBEB_STREAM_MAX) { pthread_mutex_unlock(&ctx->mutex); return CUBEB_ERROR; } ctx->active_streams += 1; pthread_mutex_unlock(&ctx->mutex); stm = calloc(1, sizeof(*stm)); assert(stm); stm->context = ctx; stm->data_callback = data_callback; stm->state_callback = state_callback; stm->user_ptr = user_ptr; stm->params = stream_params; stm->state = INACTIVE; r = pthread_mutex_init(&stm->mutex, NULL); assert(r == 0); r = alsa_locked_pcm_open(&stm->pcm, SND_PCM_STREAM_PLAYBACK, ctx->local_config); if (r < 0) { alsa_stream_destroy(stm); return CUBEB_ERROR; } r = snd_pcm_nonblock(stm->pcm, 1); assert(r == 0); /* Ugly hack: the PA ALSA plugin allows buffer configurations that can't possibly work. See https://bugzilla.mozilla.org/show_bug.cgi?id=761274. Only resort to this hack if the handle_underrun workaround failed. */ if (!ctx->local_config && ctx->is_pa) { latency = latency < 500 ? 500 : latency; } r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED, stm->params.channels, stm->params.rate, 1, latency * 1000); if (r < 0) { alsa_stream_destroy(stm); return CUBEB_ERROR_INVALID_FORMAT; } r = snd_pcm_get_params(stm->pcm, &stm->buffer_size, &stm->period_size); assert(r == 0); stm->nfds = snd_pcm_poll_descriptors_count(stm->pcm); assert(stm->nfds > 0); stm->saved_fds = calloc(stm->nfds, sizeof(struct pollfd)); assert(stm->saved_fds); r = snd_pcm_poll_descriptors(stm->pcm, stm->saved_fds, stm->nfds); assert((nfds_t) r == stm->nfds); r = pthread_cond_init(&stm->cond, NULL); assert(r == 0); if (alsa_register_stream(ctx, stm) != 0) { alsa_stream_destroy(stm); return CUBEB_ERROR; } *stream = stm; return CUBEB_OK; }
static int alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, cubeb_devid input_device, cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) { (void)stream_name; cubeb_stream * stm; int r; snd_pcm_format_t format; snd_pcm_uframes_t period_size; int latency_us = 0; assert(ctx && stream); if (input_stream_params) { /* Capture support not yet implemented. */ return CUBEB_ERROR_NOT_SUPPORTED; } if (input_device || output_device) { /* Device selection not yet implemented. */ return CUBEB_ERROR_DEVICE_UNAVAILABLE; } *stream = NULL; switch (output_stream_params->format) { case CUBEB_SAMPLE_S16LE: format = SND_PCM_FORMAT_S16_LE; break; case CUBEB_SAMPLE_S16BE: format = SND_PCM_FORMAT_S16_BE; break; case CUBEB_SAMPLE_FLOAT32LE: format = SND_PCM_FORMAT_FLOAT_LE; break; case CUBEB_SAMPLE_FLOAT32BE: format = SND_PCM_FORMAT_FLOAT_BE; break; default: return CUBEB_ERROR_INVALID_FORMAT; } pthread_mutex_lock(&ctx->mutex); if (ctx->active_streams >= CUBEB_STREAM_MAX) { pthread_mutex_unlock(&ctx->mutex); return CUBEB_ERROR; } ctx->active_streams += 1; pthread_mutex_unlock(&ctx->mutex); stm = calloc(1, sizeof(*stm)); assert(stm); stm->context = ctx; stm->data_callback = data_callback; stm->state_callback = state_callback; stm->user_ptr = user_ptr; stm->params = *output_stream_params; stm->state = INACTIVE; stm->volume = 1.0; r = pthread_mutex_init(&stm->mutex, NULL); assert(r == 0); r = alsa_locked_pcm_open(&stm->pcm, SND_PCM_STREAM_PLAYBACK, ctx->local_config); if (r < 0) { alsa_stream_destroy(stm); return CUBEB_ERROR; } r = snd_pcm_nonblock(stm->pcm, 1); assert(r == 0); latency_us = latency_frames * 1e6 / stm->params.rate; /* Ugly hack: the PA ALSA plugin allows buffer configurations that can't possibly work. See https://bugzilla.mozilla.org/show_bug.cgi?id=761274. Only resort to this hack if the handle_underrun workaround failed. */ if (!ctx->local_config && ctx->is_pa) { const int min_latency = 5e5; latency_us = latency_us < min_latency ? min_latency: latency_us; } r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED, stm->params.channels, stm->params.rate, 1, latency_us); if (r < 0) { alsa_stream_destroy(stm); return CUBEB_ERROR_INVALID_FORMAT; } r = snd_pcm_get_params(stm->pcm, &stm->buffer_size, &period_size); assert(r == 0); stm->nfds = snd_pcm_poll_descriptors_count(stm->pcm); assert(stm->nfds > 0); stm->saved_fds = calloc(stm->nfds, sizeof(struct pollfd)); assert(stm->saved_fds); r = snd_pcm_poll_descriptors(stm->pcm, stm->saved_fds, stm->nfds); assert((nfds_t) r == stm->nfds); r = pthread_cond_init(&stm->cond, NULL); assert(r == 0); if (alsa_register_stream(ctx, stm) != 0) { alsa_stream_destroy(stm); return CUBEB_ERROR; } *stream = stm; return CUBEB_OK; }