static pa_stream *connect_playback_stream(ALCdevice *device, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap) { pulse_data *data = device->ExtraData; pa_stream_state_t state; pa_stream *stream; stream = pa_stream_new(data->context, "Playback Stream", spec, chanmap); if(!stream) { ERR("pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(data->context))); return NULL; } pa_stream_set_state_callback(stream, stream_state_callback, data->loop); AL_PRINT("Attempting flags 0x%x\n", flags); if (attr) { AL_PRINT("maxlength: %d tlegth: %d prebuf: %d minreq: %d fragsize: %d\n", attr->maxlength, attr->tlength, attr->prebuf, attr->minreq, attr->fragsize); } if(pa_stream_connect_playback(stream, data->device_name, attr, flags, NULL, NULL) < 0) { ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(data->context))); pa_stream_unref(stream); return NULL; } while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) { if(!PA_STREAM_IS_GOOD(state)) { ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(data->context))); pa_stream_unref(stream); return NULL; } pa_threaded_mainloop_wait(data->loop); } pa_stream_set_state_callback(stream, NULL, NULL); return stream; }
/** * Create, set up and connect a context. * * Caller must lock the main loop. * * @return true on success, false on error */ static bool pulse_output_setup_stream(struct pulse_output *po, const pa_sample_spec *ss, GError **error_r) { assert(po != NULL); assert(po->context != NULL); po->stream = pa_stream_new(po->context, po->name, ss, NULL); if (po->stream == NULL) { g_set_error(error_r, pulse_output_quark(), 0, "pa_stream_new() has failed: %s", pa_strerror(pa_context_errno(po->context))); return false; } #if PA_CHECK_VERSION(0,9,8) pa_stream_set_suspended_callback(po->stream, pulse_output_stream_suspended_cb, po); #endif pa_stream_set_state_callback(po->stream, pulse_output_stream_state_cb, po); pa_stream_set_write_callback(po->stream, pulse_output_stream_write_cb, po); return true; }
int PulseAudioDriver::thread_body() { m_main_loop = pa_mainloop_new(); pa_mainloop_api* api = pa_mainloop_get_api(m_main_loop); pa_io_event* ioev = api->io_new(api, m_pipe[0], PA_IO_EVENT_INPUT, pipe_callback, this); m_ctx = pa_context_new(api, "Hydrogen"); pa_context_set_state_callback(m_ctx, ctx_state_callback, this); pa_context_connect(m_ctx, 0, pa_context_flags_t(0), 0); int retval; pa_mainloop_run(m_main_loop, &retval); if (m_stream) { pa_stream_set_state_callback(m_stream, 0, 0); pa_stream_set_write_callback(m_stream, 0, 0); pa_stream_unref(m_stream); m_stream = 0; } api->io_free(ioev); pa_context_unref(m_ctx); pa_mainloop_free(m_main_loop); return retval; }
void QPulseAudioInput::close() { if (!m_opened) return; m_timer->stop(); QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); if (m_stream) { pulseEngine->lock(); pa_stream_set_state_callback(m_stream, 0, 0); pa_stream_set_read_callback(m_stream, 0, 0); pa_stream_set_underflow_callback(m_stream, 0, 0); pa_stream_set_overflow_callback(m_stream, 0, 0); pa_stream_disconnect(m_stream); pa_stream_unref(m_stream); m_stream = 0; pulseEngine->unlock(); } disconnect(pulseEngine, &QPulseAudioEngine::contextFailed, this, &QPulseAudioInput::onPulseContextFailed); if (!m_pullMode && m_audioSource) { delete m_audioSource; m_audioSource = 0; } m_opened = false; }
void PulseAudioDriver::ctx_state_callback(pa_context* ctx, void* udata) { PulseAudioDriver* self = (PulseAudioDriver*)udata; pa_context_state s = pa_context_get_state(ctx); if (s == PA_CONTEXT_READY) { pa_sample_spec spec; spec.format = PA_SAMPLE_S16LE; spec.rate = self->m_sample_rate; spec.channels = 2; self->m_stream = pa_stream_new(ctx, "Hydrogen", &spec, 0); pa_stream_set_state_callback(self->m_stream, stream_state_callback, self); pa_stream_set_write_callback(self->m_stream, stream_write_callback, self); pa_buffer_attr bufattr; bufattr.fragsize = (uint32_t)-1; bufattr.maxlength = self->m_buffer_size * 4; bufattr.minreq = 0; bufattr.prebuf = (uint32_t)-1; bufattr.tlength = self->m_buffer_size * 4; pa_stream_connect_playback(self->m_stream, 0, &bufattr, pa_stream_flags_t(0), 0, 0); } else if (s == PA_CONTEXT_FAILED) pa_mainloop_quit(self->m_main_loop, 1); }
/** * Pulseaudio context state callback */ static void context_state_callback (pa_context * c, void *userdata) { GNUNET_assert (c); switch (pa_context_get_state (c)) { case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: { int r; pa_buffer_attr na; GNUNET_assert (!stream_in); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connection established.\n")); if (! (stream_in = pa_stream_new (c, "GNUNET_VoIP recorder", &sample_spec, NULL))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_stream_new() failed: %s\n"), pa_strerror (pa_context_errno (c))); goto fail; } pa_stream_set_state_callback (stream_in, &stream_state_callback, NULL); pa_stream_set_read_callback (stream_in, &stream_read_callback, NULL); memset (&na, 0, sizeof (na)); na.maxlength = UINT32_MAX; na.fragsize = pcm_length; if ((r = pa_stream_connect_record (stream_in, NULL, &na, PA_STREAM_ADJUST_LATENCY)) < 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_stream_connect_record() failed: %s\n"), pa_strerror (pa_context_errno (c))); goto fail; } break; } case PA_CONTEXT_TERMINATED: quit (0); break; case PA_CONTEXT_FAILED: default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Connection failure: %s\n"), pa_strerror (pa_context_errno (c))); goto fail; } return; fail: quit (1); }
static pa_stream *qpa_simple_new ( paaudio *g, const char *name, pa_stream_direction_t dir, const char *dev, const pa_sample_spec *ss, const pa_channel_map *map, const pa_buffer_attr *attr, int *rerror) { int r; pa_stream *stream; pa_threaded_mainloop_lock (g->mainloop); stream = pa_stream_new (g->context, name, ss, map); if (!stream) { goto fail; } pa_stream_set_state_callback (stream, stream_state_cb, g); pa_stream_set_read_callback (stream, stream_request_cb, g); pa_stream_set_write_callback (stream, stream_request_cb, g); if (dir == PA_STREAM_PLAYBACK) { r = pa_stream_connect_playback (stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING #ifdef PA_STREAM_ADJUST_LATENCY |PA_STREAM_ADJUST_LATENCY #endif |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); } else { r = pa_stream_connect_record (stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING #ifdef PA_STREAM_ADJUST_LATENCY |PA_STREAM_ADJUST_LATENCY #endif |PA_STREAM_AUTO_TIMING_UPDATE); } if (r < 0) { goto fail; } pa_threaded_mainloop_unlock (g->mainloop); return stream; fail: pa_threaded_mainloop_unlock (g->mainloop); if (stream) { pa_stream_unref (stream); } *rerror = pa_context_errno (g->context); return NULL; }
void eventd_sound_pulseaudio_play_data(EventdSoundPulseaudioContext *context, gpointer data, gsize length, gint format, guint32 rate, guint8 channels) { pa_sample_spec sample_spec; pa_stream *stream; EventdSoundPulseaudioEventData *event_data; if ( data == NULL ) return; if ( ( context == NULL ) || ( pa_context_get_state(context->context) != PA_CONTEXT_READY ) ) { g_free(data); return; } switch ( format ) { case SF_FORMAT_PCM_16: case SF_FORMAT_PCM_U8: case SF_FORMAT_PCM_S8: sample_spec.format = PA_SAMPLE_S16NE; break; case SF_FORMAT_PCM_24: sample_spec.format = PA_SAMPLE_S24NE; break; case SF_FORMAT_PCM_32: sample_spec.format = PA_SAMPLE_S32NE; break; case SF_FORMAT_FLOAT: case SF_FORMAT_DOUBLE: sample_spec.format = PA_SAMPLE_FLOAT32NE; break; default: g_warning("Unsupported format"); return; } sample_spec.rate = rate; sample_spec.channels = channels; if ( ! pa_sample_spec_valid(&sample_spec) ) { g_warning("Invalid spec"); return; } stream = pa_stream_new(context->context, "sndfile plugin playback", &sample_spec, NULL); event_data = g_new0(EventdSoundPulseaudioEventData, 1); event_data->data = data; event_data->length = length; pa_stream_set_state_callback(stream, _eventd_sound_pulseaudio_stream_state_callback, event_data); pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL); }
static pa_stream *connect_playback_stream(ALCdevice *device, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap) { pulse_data *data = device->ExtraData; pa_stream_state_t state; pa_stream *stream; stream = pa_stream_new(data->context, "Playback Stream", spec, chanmap); if(!stream) { ERR("pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(data->context))); return NULL; } pa_stream_set_state_callback(stream, stream_state_callback, data->loop); if(pa_stream_connect_playback(stream, data->device_name, attr, flags, NULL, NULL) < 0) { ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(data->context))); pa_stream_unref(stream); return NULL; } while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) { if(!PA_STREAM_IS_GOOD(state)) { ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(data->context))); pa_stream_unref(stream); return NULL; } pa_threaded_mainloop_wait(data->loop); } pa_stream_set_state_callback(stream, NULL, NULL); return stream; }
JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_pulseaudio_PA_stream_1set_1state_1callback (JNIEnv *env, jclass clazz, jlong s, jobject cb) { jweak weakCb = cb ? (*env)->NewWeakGlobalRef(env, cb) : NULL; pa_stream_set_state_callback( (pa_stream *) (intptr_t) s, weakCb ? PulseAudio_streamStateCallback : NULL, (void *) weakCb); }
void QPulseAudioThread::reconnect(SourceContainer::const_iterator pos = s_sourceList.end()) { if (s_sourceList.empty()) return; if (pos != s_sourceList.end()) { s_sourcePosition = pos; qDebug() << "reconnecting with" << *pos; } else s_sourcePosition = scanForPlaybackMonitor(); if (s_sourcePosition == s_sourceList.end()) { s_sourcePosition = s_sourceList.begin(); } if (stream && (pa_stream_get_state(stream) == PA_STREAM_READY)) { //qDebug() << "disconnect"; pa_stream_disconnect ( stream ); // pa_stream_unref(stream); //qDebug() << "* return *"; } if ( ! ( stream = pa_stream_new ( context, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL ) ) ) { fprintf ( stderr, "pa_stream_new() failed: %s\n", pa_strerror ( pa_context_errno ( context ) ) ); return; } pa_stream_set_state_callback ( stream, stream_state_callback, &s_sourceList ); pa_stream_set_read_callback ( stream, stream_read_callback, &s_sourceList ); pa_stream_set_moved_callback(stream, stream_moved_callback, &s_sourceList ); switch (pa_stream_get_state(stream)) { case PA_STREAM_UNCONNECTED:// The stream is not yet connected to any sink or source. qDebug() << "unconnected: connecting..."; connectHelper(s_sourcePosition); break; case PA_STREAM_CREATING ://The stream is being created. break; case PA_STREAM_READY :// The stream is established, you may pass audio data to it now. qDebug() << "stream is still ready, waiting for callback..."; break; case PA_STREAM_FAILED :// An error occured that made the stream invalid. qDebug() << "stream is now invalid. great."; break; case PA_STREAM_TERMINATED:// The stream has been terminated cleanly. qDebug() << "terminated..."; break; } }
/* * Context state callbacks * * A 'context' represents the connection handle between a PulseAudio * client and its server. It multiplexes everything in that connection * including data streams , bi-directional commands, and events. */ static void context_state_callback(pa_context *context, void *userdata) { struct context *ctx = userdata; struct audio_file *file; pa_stream *stream; int ret; assert(ctx); assert((file = ctx->file)); switch (pa_context_get_state(context)) { case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: out("Connection established with PulseAudio sound server"); for (int i = 0; i < 256; i++) { stream = pa_stream_new(context, "playback stream", &file->spec, NULL); if (!stream) goto fail; pa_stream_set_state_callback(stream, stream_state_callback, userdata); pa_stream_set_write_callback(stream, stream_write_callback, userdata); /* Connect this stream with a sink chosen by PulseAudio */ ret = pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL); if (ret < 0) { error("pa_stream_connect_playback() failed: %s", pa_strerror(pa_context_errno(context))); goto fail; } } break; case PA_CONTEXT_TERMINATED: exit(EXIT_SUCCESS); break; case PA_CONTEXT_FAILED: default: error("PulseAudio context connection failure: %s", pa_strerror(pa_context_errno(context))); goto fail; } return; fail: quit(ctx, EXIT_FAILURE); }
static pa_stream *connect_record_stream(const char *device_name, pa_threaded_mainloop *loop, pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap) { pa_stream_state_t state; pa_stream *stream; stream = pa_stream_new_with_proplist(context, "Capture Stream", spec, chanmap, prop_filter); if(!stream) { ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); return NULL; } pa_stream_set_state_callback(stream, stream_state_callback, loop); if(pa_stream_connect_record(stream, device_name, attr, flags) < 0) { ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); pa_stream_unref(stream); return NULL; } while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) { if(!PA_STREAM_IS_GOOD(state)) { ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); pa_stream_unref(stream); return NULL; } pa_threaded_mainloop_wait(loop); } pa_stream_set_state_callback(stream, NULL, NULL); return stream; }
static int instream_open_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoInStream *instream = &is->pub; if ((unsigned)instream->layout.channel_count > PA_CHANNELS_MAX) return SoundIoErrorIncompatibleBackend; if (!instream->name) instream->name = "SoundIoInStream"; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; SOUNDIO_ATOMIC_STORE(ispa->stream_ready, false); pa_threaded_mainloop_lock(sipa->main_loop); pa_sample_spec sample_spec; sample_spec.format = to_pulseaudio_format(instream->format); sample_spec.rate = instream->sample_rate; sample_spec.channels = instream->layout.channel_count; pa_channel_map channel_map = to_pulseaudio_channel_map(&instream->layout); ispa->stream = pa_stream_new(sipa->pulse_context, instream->name, &sample_spec, &channel_map); if (!ispa->stream) { pa_threaded_mainloop_unlock(sipa->main_loop); instream_destroy_pa(si, is); return SoundIoErrorNoMem; } pa_stream *stream = ispa->stream; pa_stream_set_state_callback(stream, recording_stream_state_callback, is); pa_stream_set_read_callback(stream, recording_stream_read_callback, is); ispa->buffer_attr.maxlength = UINT32_MAX; ispa->buffer_attr.tlength = UINT32_MAX; ispa->buffer_attr.prebuf = 0; ispa->buffer_attr.minreq = UINT32_MAX; ispa->buffer_attr.fragsize = UINT32_MAX; if (instream->software_latency > 0.0) { int bytes_per_second = instream->bytes_per_frame * instream->sample_rate; int buffer_length = instream->bytes_per_frame * ceil_dbl_to_int(instream->software_latency * bytes_per_second / (double)instream->bytes_per_frame); ispa->buffer_attr.fragsize = buffer_length; } pa_threaded_mainloop_unlock(sipa->main_loop); return 0; }
/* This is called whenever the context status changes */ static void context_state_callback(pa_context *c, void *userdata) { fail_unless(c != NULL); switch (pa_context_get_state(c)) { case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: { int i; fprintf(stderr, "Connection established.\n"); for (i = 0; i < NSTREAMS; i++) { char name[64]; pa_format_info *formats[1]; formats[0] = pa_format_info_new(); formats[0]->encoding = PA_ENCODING_PCM; pa_format_info_set_sample_format(formats[0], PA_SAMPLE_FLOAT32); pa_format_info_set_rate(formats[0], SAMPLE_HZ); pa_format_info_set_channels(formats[0], 1); fprintf(stderr, "Creating stream %i\n", i); snprintf(name, sizeof(name), "stream #%i", i); streams[i] = pa_stream_new_extended(c, name, formats, 1, NULL); fail_unless(streams[i] != NULL); pa_stream_set_state_callback(streams[i], stream_state_callback, (void*) (long) i); pa_stream_connect_playback(streams[i], NULL, &buffer_attr, PA_STREAM_START_CORKED, NULL, i == 0 ? NULL : streams[0]); pa_format_info_free(formats[0]); } break; } case PA_CONTEXT_TERMINATED: mainloop_api->quit(mainloop_api, 0); break; case PA_CONTEXT_FAILED: default: fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c))); fail(); } }
AudioStream::~AudioStream() { pa_threaded_mainloop_lock(mainloop_); pa_stream_disconnect(audiostream_); // make sure we don't get any further callback pa_stream_set_state_callback(audiostream_, NULL, NULL); pa_stream_set_write_callback(audiostream_, NULL, NULL); pa_stream_set_underflow_callback(audiostream_, NULL, NULL); pa_stream_set_overflow_callback(audiostream_, NULL, NULL); pa_stream_unref(audiostream_); pa_threaded_mainloop_unlock(mainloop_); }
AudioStream::~AudioStream() { PulseMainLoopLock lock(mainloop_); pa_stream_disconnect(audiostream_); // make sure we don't get any further callback pa_stream_set_state_callback(audiostream_, NULL, NULL); pa_stream_set_write_callback(audiostream_, NULL, NULL); pa_stream_set_read_callback(audiostream_, NULL, NULL); pa_stream_set_moved_callback(audiostream_, NULL, NULL); pa_stream_set_underflow_callback(audiostream_, NULL, NULL); pa_stream_set_overflow_callback(audiostream_, NULL, NULL); pa_stream_unref(audiostream_); }
static void instream_destroy_pa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) { struct SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; pa_stream *stream = ispa->stream; if (stream) { pa_threaded_mainloop_lock(sipa->main_loop); pa_stream_set_state_callback(stream, NULL, NULL); pa_stream_set_read_callback(stream, NULL, NULL); pa_stream_disconnect(stream); pa_stream_unref(stream); pa_threaded_mainloop_unlock(sipa->main_loop); ispa->stream = NULL; } }
static bool preload_sample(struct audio_service *service, struct play_feedback_data *pfd) { bool result = false; struct stat st; pa_sample_spec spec; char *sample_path; if (!pfd || !pfd->name) return false; if (g_slist_find(sample_list, pfd->name)) { play_feedback_sample(pfd); play_feedback_data_free(pfd); return true; } sample_path = g_strdup_printf("%s/%s.pcm", SAMPLE_PATH, pfd->name); if (stat(sample_path, &st) != 0) goto cleanup; pfd->sample_length = st.st_size; spec.format = PA_SAMPLE_S16LE; spec.rate = 44100; spec.channels = 1; pfd->fd = open(sample_path, O_RDONLY); if (pfd->fd < 0) goto cleanup; pfd->sample_stream = pa_stream_new(service->context, pfd->name, &spec, NULL); if (!pfd->sample_stream) goto cleanup; pa_stream_set_state_callback(pfd->sample_stream, preload_stream_state_cb, pfd); pa_stream_set_write_callback(pfd->sample_stream, preload_stream_write_cb, pfd); pa_stream_connect_upload(pfd->sample_stream, pfd->sample_length); result = true; cleanup: g_free(sample_path); return result; }
/** * Frees and clears the stream. */ static void pulse_output_delete_stream(struct pulse_output *po) { assert(po != NULL); assert(po->stream != NULL); #if PA_CHECK_VERSION(0,9,8) pa_stream_set_suspended_callback(po->stream, NULL, NULL); #endif pa_stream_set_state_callback(po->stream, NULL, NULL); pa_stream_set_write_callback(po->stream, NULL, NULL); pa_stream_disconnect(po->stream); pa_stream_unref(po->stream); po->stream = NULL; }
AudioStream::AudioStream(pa_context *c, pa_threaded_mainloop *m, const char *desc, int type, int smplrate, std::string& deviceName) : audiostream_(0), mainloop_(m) { static const pa_channel_map channel_map = { 1, { PA_CHANNEL_POSITION_MONO }, }; pa_sample_spec sample_spec = { PA_SAMPLE_S16LE, // PA_SAMPLE_FLOAT32LE, smplrate, 1 }; assert(pa_sample_spec_valid(&sample_spec)); assert(pa_channel_map_valid(&channel_map)); audiostream_ = pa_stream_new(c, desc, &sample_spec, &channel_map); if (!audiostream_) { ERROR("%s: pa_stream_new() failed : %s" , desc, pa_strerror(pa_context_errno(c))); throw std::runtime_error("Could not create stream\n"); } pa_buffer_attr attributes; attributes.maxlength = pa_usec_to_bytes(160 * PA_USEC_PER_MSEC, &sample_spec); attributes.tlength = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec); attributes.prebuf = 0; attributes.fragsize = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec); attributes.minreq = (uint32_t) -1; pa_threaded_mainloop_lock(mainloop_); if (type == PLAYBACK_STREAM || type == RINGTONE_STREAM) pa_stream_connect_playback(audiostream_, deviceName == "" ? NULL : deviceName.c_str(), &attributes, (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL); else if (type == CAPTURE_STREAM) pa_stream_connect_record(audiostream_, deviceName == "" ? NULL : deviceName.c_str(), &attributes, (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE)); pa_threaded_mainloop_unlock(mainloop_); pa_stream_set_state_callback(audiostream_, stream_state_callback, NULL); }
int sa_stream_open(sa_stream_t *s) { if (s == NULL) { return SA_ERROR_NO_INIT; } if (s->stream != NULL) { return SA_ERROR_INVALID; } pa_threaded_mainloop_lock(s->m); if (!(s->stream = pa_stream_new(s->context, s->client_name, &s->sample_spec, NULL))) { fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(s->context))); goto unlock_and_fail; } pa_stream_set_state_callback(s->stream, stream_state_callback, s); pa_stream_set_write_callback(s->stream, stream_write_callback, s); pa_stream_set_latency_update_callback(s->stream, stream_latency_update_callback, s); if (pa_stream_connect_playback(s->stream, NULL, NULL, 0, NULL, NULL) < 0) { fprintf(stderr, "pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(s->context))); goto unlock_and_fail; } /* Wait until the stream is ready */ pa_threaded_mainloop_wait(s->m); if (pa_stream_get_state(s->stream) != PA_STREAM_READY) { fprintf(stderr, "Failed to connect stream: %s", pa_strerror(pa_context_errno(s->context))); goto unlock_and_fail; } pa_threaded_mainloop_unlock(s->m); if (!s->stream) return SA_ERROR_NO_DEVICE; return SA_SUCCESS; unlock_and_fail: pa_threaded_mainloop_unlock(s->m); return SA_ERROR_NO_DEVICE; }
static void outstream_destroy_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; pa_stream *stream = ospa->stream; if (stream) { pa_threaded_mainloop_lock(sipa->main_loop); pa_stream_set_write_callback(stream, NULL, NULL); pa_stream_set_state_callback(stream, NULL, NULL); pa_stream_set_underflow_callback(stream, NULL, NULL); pa_stream_set_overflow_callback(stream, NULL, NULL); pa_stream_disconnect(stream); pa_stream_unref(stream); pa_threaded_mainloop_unlock(sipa->main_loop); ospa->stream = NULL; } }
void QSoundEffectPrivate::decoderReady() { if (m_waveDecoder->size() >= PA_SCACHE_ENTRY_SIZE_MAX) { m_waveDecoder->deleteLater(); qWarning("QSoundEffect(pulseaudio): Attempting to load to large a sample"); return; } if (m_name.isNull()) m_name = QString(QLatin1String("QtPulseSample-%1-%2")).arg(::getpid()).arg(quintptr(this)).toUtf8(); pa_sample_spec spec = audioFormatToSampleSpec(m_waveDecoder->audioFormat()); daemon()->lock(); pa_stream *stream = pa_stream_new(daemon()->context(), m_name.constData(), &spec, 0); pa_stream_set_state_callback(stream, stream_state_callback, this); pa_stream_set_write_callback(stream, stream_write_callback, this); pa_stream_connect_upload(stream, (size_t)m_waveDecoder->size()); m_pulseStream = stream; daemon()->unlock(); }
/* This is called whenever the context status changes */ static void context_state_callback(pa_context *c, void *userdata) { fail_unless(c != NULL); switch (pa_context_get_state(c)) { case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: { int i; fprintf(stderr, "Connection established.\n"); for (i = 0; i < NSTREAMS; i++) { char name[64]; fprintf(stderr, "Creating stream %i\n", i); snprintf(name, sizeof(name), "stream #%i", i); streams[i] = pa_stream_new(c, name, &sample_spec, NULL); fail_unless(streams[i] != NULL); pa_stream_set_state_callback(streams[i], stream_state_callback, (void*) (long) i); pa_stream_connect_playback(streams[i], NULL, &buffer_attr, PA_STREAM_START_CORKED, NULL, i == 0 ? NULL : streams[0]); } break; } case PA_CONTEXT_TERMINATED: mainloop_api->quit(mainloop_api, 0); break; case PA_CONTEXT_FAILED: default: fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c))); fail(); } }
static void __context_get_sink_info_callback(pa_context* context, const pa_sink_info* info, int is_last, void* data) { guac_client* client = (guac_client*) data; pa_stream* stream; pa_sample_spec spec; pa_buffer_attr attr; /* Stop if end of list reached */ if (is_last) return; guac_client_log_info(client, "Starting streaming from \"%s\"", info->description); /* Set format */ spec.format = PA_SAMPLE_S16LE; spec.rate = GUAC_VNC_AUDIO_RATE; spec.channels = GUAC_VNC_AUDIO_CHANNELS; attr.maxlength = -1; attr.fragsize = GUAC_VNC_AUDIO_FRAGMENT_SIZE; /* Create stream */ stream = pa_stream_new(context, "Guacamole Audio", &spec, NULL); /* Set stream callbacks */ pa_stream_set_state_callback(stream, __stream_state_callback, client); pa_stream_set_read_callback(stream, __stream_read_callback, client); /* Start stream */ pa_stream_connect_record(stream, info->monitor_source_name, &attr, PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND | PA_STREAM_ADJUST_LATENCY); }
void RageSoundDriver_PulseAudio::m_InitStream(void) { int error; pa_sample_spec ss; pa_channel_map map; /* init sample spec */ ss.format = PA_SAMPLE_S16LE; ss.channels = 2; ss.rate = PREFSMAN->m_iSoundPreferredSampleRate; if(ss.rate == 0) { ss.rate = 44100; } /* init channel map */ pa_channel_map_init_stereo(&map); /* check sample spec */ if(!pa_sample_spec_valid(&ss)) { if(asprintf(&m_Error, "invalid sample spec!") == -1) { m_Error = nullptr; } m_Sem.Post(); return; } /* log the used sample spec */ char specstring[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(specstring, sizeof(specstring), &ss); LOG->Trace("Pulse: using sample spec: %s", specstring); /* create the stream */ LOG->Trace("Pulse: pa_stream_new()..."); m_PulseStream = pa_stream_new(m_PulseCtx, "Stepmania Audio", &ss, &map); if(m_PulseStream == nullptr) { if(asprintf(&m_Error, "pa_stream_new(): %s", pa_strerror(pa_context_errno(m_PulseCtx))) == -1) { m_Error = nullptr; } m_Sem.Post(); return; } /* set the write callback, it will be called when the sound server * needs data */ pa_stream_set_write_callback(m_PulseStream, StaticStreamWriteCb, this); /* set the state callback, it will be called the the stream state will * change */ pa_stream_set_state_callback(m_PulseStream, StaticStreamStateCb, this); /* configure attributes of the stream */ pa_buffer_attr attr; memset(&attr, 0x00, sizeof(attr)); /* tlength: Target length of the buffer. * * "The server tries to assure that at least tlength bytes are always * available in the per-stream server-side playback buffer. It is * recommended to set this to (uint32_t) -1, which will initialize * this to a value that is deemed sensible by the server. However, * this value will default to something like 2s, i.e. for applications * that have specific latency requirements this value should be set to * the maximum latency that the application can deal with." * * We don't want the default here, we want a small latency. * We use pa_usec_to_bytes() to convert a latency to a buffer size. */ attr.tlength = pa_usec_to_bytes(20*PA_USEC_PER_MSEC, &ss); /* maxlength: Maximum length of the buffer * * "Setting this to (uint32_t) -1 will initialize this to the maximum * value supported by server, which is recommended." * * (uint32_t)-1 is NOT working here, setting it to tlength*2, like * openal-soft-pulseaudio does. */ attr.maxlength = attr.tlength*2; /* minreq: Minimum request * * "The server does not request less than minreq bytes from the client, * instead waits until the buffer is free enough to request more bytes * at once. It is recommended to set this to (uint32_t) -1, which will * initialize this to a value that is deemed sensible by the server." * * (uint32_t)-1 is NOT working here, setting it to 0, like * openal-soft-pulseaudio does. */ attr.minreq = 0; /* prebuf: Pre-buffering * * "The server does not start with playback before at least prebuf * bytes are available in the buffer. It is recommended to set this * to (uint32_t) -1, which will initialize this to the same value as * tlength" */ attr.prebuf = (uint32_t)-1; /* log the used target buffer length */ LOG->Trace("Pulse: using target buffer length of %i bytes", attr.tlength); /* connect the stream for playback */ LOG->Trace("Pulse: pa_stream_connect_playback()..."); error = pa_stream_connect_playback(m_PulseStream, nullptr, &attr, PA_STREAM_AUTO_TIMING_UPDATE, nullptr, nullptr); if(error < 0) { if(asprintf(&m_Error, "pa_stream_connect_playback(): %s", pa_strerror(pa_context_errno(m_PulseCtx))) == -1) { m_Error = nullptr; } m_Sem.Post(); return; } m_SampleRate = ss.rate; }
AudioStream::AudioStream(pa_context *c, pa_threaded_mainloop *m, const char *desc, int type, unsigned samplrate, const PaDeviceInfos* infos, bool ec) : audiostream_(0), mainloop_(m) { const pa_channel_map channel_map = infos->channel_map; pa_sample_spec sample_spec = { PA_SAMPLE_S16LE, // PA_SAMPLE_FLOAT32LE, samplrate, channel_map.channels }; RING_DBG("%s: trying to create stream with device %s (%dHz, %d channels)", desc, infos->name.c_str(), samplrate, channel_map.channels); assert(pa_sample_spec_valid(&sample_spec)); assert(pa_channel_map_valid(&channel_map)); std::unique_ptr<pa_proplist, decltype(pa_proplist_free)&> pl (pa_proplist_new(), pa_proplist_free); pa_proplist_sets(pl.get(), PA_PROP_FILTER_WANT, "echo-cancel"); audiostream_ = pa_stream_new_with_proplist(c, desc, &sample_spec, &channel_map, ec ? pl.get() : nullptr); if (!audiostream_) { RING_ERR("%s: pa_stream_new() failed : %s" , desc, pa_strerror(pa_context_errno(c))); throw std::runtime_error("Could not create stream\n"); } pa_buffer_attr attributes; attributes.maxlength = pa_usec_to_bytes(160 * PA_USEC_PER_MSEC, &sample_spec); attributes.tlength = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec); attributes.prebuf = 0; attributes.fragsize = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec); attributes.minreq = (uint32_t) -1; { PulseMainLoopLock lock(mainloop_); const pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE); if (type == PLAYBACK_STREAM || type == RINGTONE_STREAM) { pa_stream_connect_playback(audiostream_, infos->name.empty() ? NULL : infos->name.c_str(), &attributes, flags, NULL, NULL); } else if (type == CAPTURE_STREAM) { pa_stream_connect_record(audiostream_, infos->name.empty() ? NULL : infos->name.c_str(), &attributes, flags); } } pa_stream_set_state_callback(audiostream_, [](pa_stream* s, void* user_data){ static_cast<AudioStream*>(user_data)->stateChanged(s); }, this); pa_stream_set_moved_callback(audiostream_, [](pa_stream* s, void* user_data){ static_cast<AudioStream*>(user_data)->moved(s); }, this); }
static void *pulse_init(const char *device, unsigned rate, unsigned latency) { pa_sample_spec spec; pa_t *pa; pa_buffer_attr buffer_attr = {0}; const pa_buffer_attr *server_attr = NULL; memset(&spec, 0, sizeof(spec)); pa = (pa_t*)calloc(1, sizeof(*pa)); if (!pa) goto error; pa->mainloop = pa_threaded_mainloop_new(); if (!pa->mainloop) goto error; pa->context = pa_context_new(pa_threaded_mainloop_get_api(pa->mainloop), "RetroArch"); if (!pa->context) goto error; pa_context_set_state_callback(pa->context, context_state_cb, pa); if (pa_context_connect(pa->context, device, PA_CONTEXT_NOFLAGS, NULL) < 0) goto error; pa_threaded_mainloop_lock(pa->mainloop); if (pa_threaded_mainloop_start(pa->mainloop) < 0) goto error; pa_threaded_mainloop_wait(pa->mainloop); if (pa_context_get_state(pa->context) != PA_CONTEXT_READY) goto unlock_error; spec.format = is_little_endian() ? PA_SAMPLE_FLOAT32LE : PA_SAMPLE_FLOAT32BE; spec.channels = 2; spec.rate = rate; pa->stream = pa_stream_new(pa->context, "audio", &spec, NULL); if (!pa->stream) goto unlock_error; pa_stream_set_state_callback(pa->stream, stream_state_cb, pa); pa_stream_set_write_callback(pa->stream, stream_request_cb, pa); pa_stream_set_latency_update_callback(pa->stream, stream_latency_update_cb, pa); pa_stream_set_underflow_callback(pa->stream, underrun_update_cb, pa); pa_stream_set_buffer_attr_callback(pa->stream, buffer_attr_cb, pa); buffer_attr.maxlength = -1; buffer_attr.tlength = pa_usec_to_bytes(latency * PA_USEC_PER_MSEC, &spec); buffer_attr.prebuf = -1; buffer_attr.minreq = -1; buffer_attr.fragsize = -1; if (pa_stream_connect_playback(pa->stream, NULL, &buffer_attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0) goto error; pa_threaded_mainloop_wait(pa->mainloop); if (pa_stream_get_state(pa->stream) != PA_STREAM_READY) goto unlock_error; server_attr = pa_stream_get_buffer_attr(pa->stream); if (server_attr) { pa->buffer_size = server_attr->tlength; RARCH_LOG("[PulseAudio]: Requested %u bytes buffer, got %u.\n", (unsigned)buffer_attr.tlength, (unsigned)pa->buffer_size); } else pa->buffer_size = buffer_attr.tlength; pa_threaded_mainloop_unlock(pa->mainloop); return pa; unlock_error: pa_threaded_mainloop_unlock(pa->mainloop); error: pulse_free(pa); return NULL; }
bool CPulseAESound::Initialize() { /* we dont re-init the wav loader in PA as PA handles the samplerate */ if (!m_wavLoader.IsValid()) return false; m_sampleSpec.format = PA_SAMPLE_FLOAT32NE; m_sampleSpec.rate = m_wavLoader.GetSampleRate(); m_sampleSpec.channels = m_wavLoader.GetChannelLayout().Count(); if (!pa_sample_spec_valid(&m_sampleSpec)) { CLog::Log(LOGERROR, "CPulseAESound::Initialize - Invalid sample spec"); return false; } struct pa_channel_map map; map.channels = m_sampleSpec.channels; switch (map.channels) { case 1: map.map[0] = PA_CHANNEL_POSITION_MONO; break; case 2: map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; break; default: CLog::Log(LOGERROR, "CPulseAESound::Initialize - We do not yet support multichannel sounds"); return false; } m_maxVolume = CAEFactory::GetEngine()->GetVolume(); m_volume = 1.0f; pa_volume_t paVolume = pa_sw_volume_from_linear((double)(m_volume * m_maxVolume)); pa_cvolume_set(&m_chVolume, m_sampleSpec.channels, paVolume); pa_threaded_mainloop_lock(m_mainLoop); if ((m_stream = pa_stream_new(m_context, m_pulseName.c_str(), &m_sampleSpec, &map)) == NULL) { CLog::Log(LOGERROR, "CPulseAESound::Initialize - Could not create a stream"); pa_threaded_mainloop_unlock(m_mainLoop); return false; } pa_stream_set_state_callback(m_stream, CPulseAESound::StreamStateCallback, this); pa_stream_set_write_callback(m_stream, CPulseAESound::StreamWriteCallback, this); if (pa_stream_connect_upload(m_stream, m_wavLoader.GetFrameCount() * pa_frame_size(&m_sampleSpec)) != 0) { CLog::Log(LOGERROR, "CPulseAESound::Initialize - Could not initialize the stream"); pa_stream_disconnect(m_stream); m_stream = NULL; pa_threaded_mainloop_unlock(m_mainLoop); return false; } /* check if the stream failed */ if (pa_stream_get_state(m_stream) == PA_STREAM_FAILED) { CLog::Log(LOGERROR, "CPulseAESound::Initialize - Waited for the stream but it failed"); pa_stream_disconnect(m_stream); m_stream = NULL; pa_threaded_mainloop_unlock(m_mainLoop); return false; } pa_threaded_mainloop_unlock(m_mainLoop); return true; }