gboolean xmms_pulse_backend_write (xmms_pulse *p, const char *data, size_t length, int *rerror) { assert (p); if (!data || !length) { if (rerror) *rerror = PA_ERR_INVALID; return FALSE; } pa_threaded_mainloop_lock (p->mainloop); if (!check_pulse_health (p, rerror)) goto unlock_and_fail; while (length > 0) { size_t buf_len; int ret; while (!(buf_len = pa_stream_writable_size (p->stream))) { pa_threaded_mainloop_wait (p->mainloop); if (!check_pulse_health (p, rerror)) goto unlock_and_fail; } if (buf_len == (size_t)-1) { if (rerror) *rerror = pa_context_errno ((p)->context); goto unlock_and_fail; } if (buf_len > length) buf_len = length; ret = pa_stream_write (p->stream, data, buf_len, NULL, 0, PA_SEEK_RELATIVE); if (ret < 0) { if (rerror) *rerror = pa_context_errno ((p)->context); goto unlock_and_fail; } data += buf_len; length -= buf_len; } pa_threaded_mainloop_unlock (p->mainloop); return TRUE; unlock_and_fail: pa_threaded_mainloop_unlock (p->mainloop); return FALSE; }
static void gst_pulsesrc_reset (GstAudioSrc * asrc) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_operation *o = NULL; pa_threaded_mainloop_lock (pulsesrc->mainloop); GST_DEBUG_OBJECT (pulsesrc, "reset"); if (gst_pulsesrc_is_dead (pulsesrc, TRUE)) goto unlock_and_fail; if (!(o = pa_stream_flush (pulsesrc->stream, gst_pulsesrc_success_cb, pulsesrc))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_stream_flush() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } pulsesrc->paused = TRUE; /* Inform anyone waiting in _write() call that it shall wakeup */ if (pulsesrc->in_read) { pa_threaded_mainloop_signal (pulsesrc->mainloop, 0); } pulsesrc->operation_success = FALSE; while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) { if (gst_pulsesrc_is_dead (pulsesrc, TRUE)) goto unlock_and_fail; pa_threaded_mainloop_wait (pulsesrc->mainloop); } if (!pulsesrc->operation_success) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Flush failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } unlock_and_fail: if (o) { pa_operation_cancel (o); pa_operation_unref (o); } pa_threaded_mainloop_unlock (pulsesrc->mainloop); }
static int rdpsnd_pulse_connect(rdpsndDevicePlugin * devplugin) { struct pulse_device_data * pulse_data; pa_context_state_t state; pulse_data = (struct pulse_device_data *) devplugin->device_data; if (!pulse_data->context) return 1; if (pa_context_connect(pulse_data->context, NULL, 0, NULL)) { LLOGLN(0, ("rdpsnd_pulse_connect: pa_context_connect failed (%d)", pa_context_errno(pulse_data->context))); return 1; } pa_threaded_mainloop_lock(pulse_data->mainloop); if (pa_threaded_mainloop_start(pulse_data->mainloop) < 0) { pa_threaded_mainloop_unlock(pulse_data->mainloop); LLOGLN(0, ("rdpsnd_pulse_connect: pa_threaded_mainloop_start failed (%d)", pa_context_errno(pulse_data->context))); return 1; } for (;;) { state = pa_context_get_state(pulse_data->context); if (state == PA_CONTEXT_READY) break; if (!PA_CONTEXT_IS_GOOD(state)) { LLOGLN(0, ("rdpsnd_pulse_connect: bad context state (%d)", pa_context_errno(pulse_data->context))); break; } pa_threaded_mainloop_wait(pulse_data->mainloop); } pa_threaded_mainloop_unlock(pulse_data->mainloop); if (state == PA_CONTEXT_READY) { LLOGLN(0, ("rdpsnd_pulse_connect: connected")); return 0; } else { pa_context_disconnect(pulse_data->context); return 1; } }
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; }
bool PulseAudio::init(bool) { pa_ml = pa_mainloop_new(); pa_mainloop_api* pa_mlapi = pa_mainloop_get_api(pa_ml); pa_context* pa_ctx = pa_context_new(pa_mlapi, "MuseScore"); if (pa_context_connect(pa_ctx, NULL, pa_context_flags_t(0), NULL) != 0) { qDebug("PulseAudio Context Connect Failed with Error: %s", pa_strerror(pa_context_errno(pa_ctx))); return false; } int pa_ready = 0; pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); while (pa_ready == 0) pa_mainloop_iterate(pa_ml, 1, NULL); if (pa_ready == 2) return false; ss.rate = _sampleRate; ss.channels = 2; ss.format = PA_SAMPLE_FLOAT32LE; pa_stream* playstream = pa_stream_new(pa_ctx, "Playback", &ss, NULL); if (!playstream) { qDebug("pa_stream_new failed: %s", pa_strerror(pa_context_errno(pa_ctx))); return false; } pa_stream_set_write_callback(playstream, paCallback, this); bufattr.fragsize = (uint32_t)-1; bufattr.maxlength = FRAMES * 2 * sizeof(float); bufattr.minreq = FRAMES * 1 * sizeof(float); // pa_usec_to_bytes(0, &ss); bufattr.prebuf = (uint32_t)-1; bufattr.tlength = bufattr.maxlength; int r = pa_stream_connect_playback(playstream, nullptr, &bufattr, PA_STREAM_NOFLAGS, nullptr, nullptr); if (r < 0) { qDebug("pa_stream_connect_playback failed"); pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); pa_ml = 0; return false; } return true; }
static void gst_pulsemixer_ctrl_timeout_event (pa_mainloop_api * a, pa_time_event * e, const struct timeval *tv, void *userdata) { pa_operation *o; GstPulseMixerCtrl *c = GST_PULSEMIXER_CTRL (userdata); if (c->update_volume) { if (c->type == GST_PULSEMIXER_SINK) o = pa_context_set_sink_volume_by_index (c->context, c->index, &c->volume, NULL, NULL); else o = pa_context_set_source_volume_by_index (c->context, c->index, &c->volume, NULL, NULL); if (!o) GST_WARNING_OBJECT (c->object, "Failed to set device volume: %s", pa_strerror (pa_context_errno (c->context))); else pa_operation_unref (o); c->update_volume = FALSE; } if (c->update_mute) { if (c->type == GST_PULSEMIXER_SINK) o = pa_context_set_sink_mute_by_index (c->context, c->index, !!c->muted, NULL, NULL); else o = pa_context_set_source_mute_by_index (c->context, c->index, !!c->muted, NULL, NULL); if (!o) GST_WARNING_OBJECT (c->object, "Failed to set device mute: %s", pa_strerror (pa_context_errno (c->context))); else pa_operation_unref (o); c->update_mute = FALSE; } /* Make sure that all outstanding queries are being ignored */ c->ignore_queries = c->outstandig_queries; g_assert (e == c->time_event); a->time_free (e); c->time_event = NULL; }
bool pulse_output_set_volume(struct pulse_output *po, const struct pa_cvolume *volume, GError **error_r) { pa_operation *o; if (po->context == NULL || po->stream == NULL || pa_stream_get_state(po->stream) != PA_STREAM_READY) { g_set_error(error_r, pulse_output_quark(), 0, "disconnected"); return false; } o = pa_context_set_sink_input_volume(po->context, pa_stream_get_index(po->stream), volume, NULL, NULL); if (o == NULL) { g_set_error(error_r, pulse_output_quark(), 0, "failed to set PulseAudio volume: %s", pa_strerror(pa_context_errno(po->context))); return false; } pa_operation_unref(o); return true; }
void PulseAudioPlayer::Stop() { if (!is_playing) return; //printf("Stopping PulseAudio\n"); is_playing = false; start_frame = 0; cur_frame = 0; end_frame = 0; // Flush the stream of data //printf("Flushing stream\n"); pa_threaded_mainloop_lock(mainloop); pa_operation *op = pa_stream_flush(stream, (pa_stream_success_cb_t)pa_stream_success, this); pa_threaded_mainloop_unlock(mainloop); stream_success.Wait(); pa_operation_unref(op); if (!stream_success_val) { paerror = pa_context_errno(context); printf("PulseAudio player: Error flushing stream: %s (%d)\n", pa_strerror(paerror), paerror); } // And unref it //printf("Stopped stream\n\n"); }
static ALCuint pulse_available_samples(ALCdevice *device) //{{{ { pulse_data *data = device->ExtraData; size_t samples; pa_threaded_mainloop_lock(data->loop); /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ samples = (device->Connected ? pa_stream_readable_size(data->stream) : 0); while(samples > 0) { const void *buf; size_t length; if(pa_stream_peek(data->stream, &buf, &length) < 0) { ERR("pa_stream_peek() failed: %s\n", pa_strerror(pa_context_errno(data->context))); break; } WriteRingBuffer(data->ring, buf, length/data->frame_size); samples -= length; pa_stream_drop(data->stream); } pa_threaded_mainloop_unlock(data->loop); return RingBufferSize(data->ring); } //}}}
static void inputStreamStateCallback(pa_stream *stream, void *userdata) { Q_UNUSED(userdata); pa_stream_state_t state = pa_stream_get_state(stream); #ifdef DEBUG_PULSE qDebug() << "Stream state: " << QPulseAudioInternal::stateToQString(state); #endif switch (state) { case PA_STREAM_CREATING: break; case PA_STREAM_READY: { #ifdef DEBUG_PULSE QPulseAudioInput *audioInput = static_cast<QPulseAudioInput*>(userdata); const pa_buffer_attr *buffer_attr = pa_stream_get_buffer_attr(stream); qDebug() << "*** maxlength: " << buffer_attr->maxlength; qDebug() << "*** prebuf: " << buffer_attr->prebuf; qDebug() << "*** fragsize: " << buffer_attr->fragsize; qDebug() << "*** minreq: " << buffer_attr->minreq; qDebug() << "*** tlength: " << buffer_attr->tlength; pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(audioInput->format()); qDebug() << "*** bytes_to_usec: " << pa_bytes_to_usec(buffer_attr->fragsize, &spec); #endif } break; case PA_STREAM_TERMINATED: break; case PA_STREAM_FAILED: default: qWarning() << QString("Stream error: %1").arg(pa_strerror(pa_context_errno(pa_stream_get_context(stream)))); QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance(); pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0); break; } }
/* Write some data to the stream */ static void do_stream_write(size_t length) { size_t l; pa_assert(length); if (!buffer || !buffer_length) return; l = length; if (l > buffer_length) l = buffer_length; if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) { pa_log(_("pa_stream_write() failed: %s"), pa_strerror(pa_context_errno(context))); quit(1); return; } buffer_length -= l; buffer_index += l; if (!buffer_length) { pa_xfree(buffer); buffer = NULL; buffer_index = buffer_length = 0; } }
/* This routine is called whenever the stream state changes */ void QPulseAudioThread::stream_state_callback ( pa_stream *s, void *userdata ) { assert ( s ); QPulseAudioThread * thread = (QPulseAudioThread *)userdata; switch ( pa_stream_get_state ( s ) ) { case PA_STREAM_UNCONNECTED: qDebug() << "UNCONNECTED"; break; case PA_STREAM_CREATING: qDebug() << "CREATED"; break; case PA_STREAM_TERMINATED: qDebug() << "TERMINATED"; break; case PA_STREAM_READY: qDebug() << "READY"; if ( verbose ) { const pa_buffer_attr *a; fprintf ( stderr, "Stream successfully created.\n" ); if ( ! ( a = pa_stream_get_buffer_attr ( s ) ) ) fprintf ( stderr, "pa_stream_get_buffer_attr() failed: %s\n", pa_strerror ( pa_context_errno ( pa_stream_get_context ( s ) ) ) ); else { fprintf(stderr, "Buffer metrics: maxlength=%u, fragsize=%u\n", a->maxlength, a->fragsize); } } break; case PA_STREAM_FAILED: qDebug() << "FAILED"; default: fprintf ( stderr, "Stream error: %s\n", pa_strerror ( pa_context_errno ( pa_stream_get_context ( s ) ) ) ); pulseQuit ( 1 ); } }
/** * Check if the stream is (already) connected, and waits if not. The * mainloop must be locked before calling this function. * * @return true on success, false on error */ static bool pulse_output_wait_stream(struct pulse_output *po, GError **error_r) { pa_stream_state_t state = pa_stream_get_state(po->stream); switch (state) { case PA_STREAM_READY: return true; case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: case PA_STREAM_UNCONNECTED: g_set_error(error_r, pulse_output_quark(), 0, "disconnected"); return false; case PA_STREAM_CREATING: break; } do { state = pulse_output_check_stream(po); } while (state == PA_STREAM_CREATING); if (state != PA_STREAM_READY) { g_set_error(error_r, pulse_output_quark(), 0, "failed to connect the stream: %s", pa_strerror(pa_context_errno(po->context))); return false; } return true; }
/** * This function does the context initialization. */ static gboolean xvd_connect_to_pulse (XvdInstance *i) { pa_context_flags_t flags = PA_CONTEXT_NOFAIL; if (i->pulse_context) { pa_context_unref (i->pulse_context); i->pulse_context = NULL; } i->pulse_context = pa_context_new (pa_glib_mainloop_get_api (i->pa_main_loop), XVD_APPNAME); g_assert(i->pulse_context); pa_context_set_state_callback (i->pulse_context, xvd_context_state_callback, i); if (pa_context_connect (i->pulse_context, NULL, flags, NULL) < 0) { g_warning ("xvd_connect_to_pulse: failed to connect context: %s", pa_strerror (pa_context_errno (i->pulse_context))); return FALSE; } return TRUE; }
static void pulse_write(void* ptr, int length) { int writeoffs, remain, writable; CHECK_CONNECTED(); pa_threaded_mainloop_lock(mainloop); CHECK_DEAD_GOTO(fail, 1); /* break large fragments into smaller fragments. --nenolod */ for (writeoffs = 0, remain = length; writeoffs < length; writeoffs += writable, remain -= writable) { void * pptr = (char *) ptr + writeoffs; writable = length - writeoffs; size_t fragsize = pa_stream_writable_size(stream); /* don't write more than what PA is willing to handle right now. */ if (writable > fragsize) writable = fragsize; if (pa_stream_write(stream, pptr, writable, NULL, PA_SEEK_RELATIVE, 0) < 0) { AUDDBG("pa_stream_write() failed: %s", pa_strerror(pa_context_errno(context))); goto fail; } } do_trigger = 0; written += length; fail: pa_threaded_mainloop_unlock(mainloop); }
int AudioOutputPulseAudio::GetBufferedOnSoundcard(void) const { pa_usec_t latency = 0; size_t buffered = 0; if (!pcontext || pa_context_get_state(pcontext) != PA_CONTEXT_READY) return 0; if (!pstream || pa_stream_get_state(pstream) != PA_STREAM_READY) return 0; const pa_buffer_attr *buf_attr = pa_stream_get_buffer_attr(pstream); size_t bfree = pa_stream_writable_size(pstream); buffered = buf_attr->tlength - bfree; pa_threaded_mainloop_lock(mainloop); while (pa_stream_get_latency(pstream, &latency, NULL) < 0) { if (pa_context_errno(pcontext) != PA_ERR_NODATA) { latency = 0; break; } pa_threaded_mainloop_wait(mainloop); } pa_threaded_mainloop_unlock(mainloop); return ((uint64_t)latency * samplerate * output_bytes_per_frame / 1000000) + buffered; }
void AudioStream::stream_state_callback(pa_stream* s, void* /*user_data*/) { char str[PA_SAMPLE_SPEC_SNPRINT_MAX]; switch (pa_stream_get_state(s)) { case PA_STREAM_CREATING: DEBUG("Stream is creating..."); break; case PA_STREAM_TERMINATED: DEBUG("Stream is terminating..."); break; case PA_STREAM_READY: DEBUG("Stream successfully created, connected to %s", pa_stream_get_device_name(s)); DEBUG("maxlength %u", pa_stream_get_buffer_attr(s)->maxlength); DEBUG("tlength %u", pa_stream_get_buffer_attr(s)->tlength); DEBUG("prebuf %u", pa_stream_get_buffer_attr(s)->prebuf); DEBUG("minreq %u", pa_stream_get_buffer_attr(s)->minreq); DEBUG("fragsize %u", pa_stream_get_buffer_attr(s)->fragsize); DEBUG("samplespec %s", pa_sample_spec_snprint(str, sizeof(str), pa_stream_get_sample_spec(s))); break; case PA_STREAM_UNCONNECTED: DEBUG("Stream unconnected"); break; case PA_STREAM_FAILED: default: ERROR("Sink/Source doesn't exists: %s" , pa_strerror(pa_context_errno(pa_stream_get_context(s)))); break; } }
static void gst_pulsemixer_ctrl_subscribe_cb (pa_context * context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { GstPulseMixerCtrl *c = GST_PULSEMIXER_CTRL (userdata); pa_operation *o = NULL; /* Called from the background thread! */ if (c->index != idx) return; if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE) return; if (c->type == GST_PULSEMIXER_SINK) o = pa_context_get_sink_info_by_index (c->context, c->index, gst_pulsemixer_ctrl_sink_info_cb, c); else o = pa_context_get_source_info_by_index (c->context, c->index, gst_pulsemixer_ctrl_source_info_cb, c); if (!o) { GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s", pa_strerror (pa_context_errno (c->context))); return; } pa_operation_unref (o); c->outstandig_queries++; }
/** * 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; }
pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { pa_usec_t t; int negative; pa_assert(p); pa_threaded_mainloop_lock(p->mainloop); for (;;) { CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) break; CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail); /* Wait until latency data is available again */ pa_threaded_mainloop_wait(p->mainloop); } pa_threaded_mainloop_unlock(p->mainloop); return negative ? 0 : t; unlock_and_fail: pa_threaded_mainloop_unlock(p->mainloop); return (pa_usec_t) -1; }
static void pulse_output_close(struct audio_output *ao) { struct pulse_output *po = (struct pulse_output *)ao; pa_operation *o; assert(po->mainloop != NULL); pa_threaded_mainloop_lock(po->mainloop); if (pa_stream_get_state(po->stream) == PA_STREAM_READY) { o = pa_stream_drain(po->stream, pulse_output_stream_success_cb, po); if (o == NULL) { g_warning("pa_stream_drain() has failed: %s", pa_strerror(pa_context_errno(po->context))); } else pulse_wait_for_operation(po->mainloop, o); } pulse_output_delete_stream(po); if (po->context != NULL && pa_context_get_state(po->context) != PA_CONTEXT_READY) pulse_output_delete_context(po); pa_threaded_mainloop_unlock(po->mainloop); }
void AudioStream::stateChanged(pa_stream* s) { UNUSED char str[PA_SAMPLE_SPEC_SNPRINT_MAX]; switch (pa_stream_get_state(s)) { case PA_STREAM_CREATING: RING_DBG("Stream is creating..."); break; case PA_STREAM_TERMINATED: RING_DBG("Stream is terminating..."); break; case PA_STREAM_READY: RING_DBG("Stream successfully created, connected to %s", pa_stream_get_device_name(s)); //RING_DBG("maxlength %u", pa_stream_get_buffer_attr(s)->maxlength); //RING_DBG("tlength %u", pa_stream_get_buffer_attr(s)->tlength); //RING_DBG("prebuf %u", pa_stream_get_buffer_attr(s)->prebuf); //RING_DBG("minreq %u", pa_stream_get_buffer_attr(s)->minreq); //RING_DBG("fragsize %u", pa_stream_get_buffer_attr(s)->fragsize); //RING_DBG("samplespec %s", pa_sample_spec_snprint(str, sizeof(str), pa_stream_get_sample_spec(s))); break; case PA_STREAM_UNCONNECTED: RING_DBG("Stream unconnected"); break; case PA_STREAM_FAILED: default: RING_ERR("Stream failure: %s" , pa_strerror(pa_context_errno(pa_stream_get_context(s)))); break; } }
static void pulse_output_cancel(struct audio_output *ao) { struct pulse_output *po = (struct pulse_output *)ao; pa_operation *o; assert(po->mainloop != NULL); assert(po->stream != NULL); pa_threaded_mainloop_lock(po->mainloop); if (pa_stream_get_state(po->stream) != PA_STREAM_READY) { /* no need to flush when the stream isn't connected yet */ pa_threaded_mainloop_unlock(po->mainloop); return; } assert(po->context != NULL); o = pa_stream_flush(po->stream, pulse_output_stream_success_cb, po); if (o == NULL) { g_warning("pa_stream_flush() has failed: %s", pa_strerror(pa_context_errno(po->context))); pa_threaded_mainloop_unlock(po->mainloop); return; } pulse_wait_for_operation(po->mainloop, o); pa_threaded_mainloop_unlock(po->mainloop); }
/* * Stream state callbacks * * A 'stream' represents a data path between the client and server. * Sample streams include a playback stream, a recording stream, or * a file upload stream. * * A single client-server connection ('context') can have multiple * streams. Each stream can have its own latency and time fragment * requirements through PulseAudio buffer attributes. A stream can * be moved to a different sink during its lifetime. */ static void stream_state_callback(pa_stream *stream, void *userdata) { struct context *ctx = userdata; assert(ctx); assert(ctx->context); switch (pa_stream_get_state(stream)) { case PA_STREAM_CREATING: case PA_STREAM_TERMINATED: break; case PA_STREAM_READY: out("Playback stream succesfully created"); break; case PA_STREAM_FAILED: default: error("Playback stream error: %s", pa_strerror(pa_context_errno(ctx->context))); goto fail; } return; fail: quit(ctx, EXIT_FAILURE); }
int xmms_pulse_backend_get_latency (xmms_pulse *p, int *rerror) { pa_usec_t t; int negative, r; assert (p); pa_threaded_mainloop_lock (p->mainloop); while (1) { if (!check_pulse_health (p, rerror)) goto unlock_and_fail; if (pa_stream_get_latency (p->stream, &t, &negative) >= 0) break; r = pa_context_errno (p->context); if (r != PA_ERR_NODATA) { if (rerror) *rerror = r; goto unlock_and_fail; } /* Wait until latency data is available again */ pa_threaded_mainloop_wait (p->mainloop); } pa_threaded_mainloop_unlock (p->mainloop); return negative ? 0 : t; unlock_and_fail: pa_threaded_mainloop_unlock (p->mainloop); return -1; }
void AudioOutputPulseAudio::SetVolumeChannel(int channel, int volume) { QString fn_log_tag = "SetVolumeChannel, "; if (channel < 0 || channel > PULSE_MAX_CHANNELS || volume < 0) { VBERROR(fn_log_tag + QString("bad volume params, channel %1, volume %2") .arg(channel).arg(volume)); return; } volume_control.values[channel] = (float)volume / 100.0f * (float)PA_VOLUME_NORM; volume = min(100, volume); volume = max(0, volume); uint32_t sink_index = pa_stream_get_device_index(pstream); pa_threaded_mainloop_lock(mainloop); pa_operation *op = pa_context_set_sink_volume_by_index(pcontext, sink_index, &volume_control, OpCompletionCallback, this); pa_threaded_mainloop_unlock(mainloop); if (op) pa_operation_unref(op); else VBERROR(fn_log_tag + QString("set sink volume operation failed, sink %1, error %2 ") .arg(sink_index).arg(pa_strerror(pa_context_errno(pcontext)))); }
static void on_pulse_context_state_change(pa_context *pa_context, AudioListContext *context) { gint error; error = pa_context_errno(pa_context); if (error) { g_warning("PulseAudio: error: %s", pa_strerror(error)); } switch (pa_context_get_state(pa_context)) { case PA_CONTEXT_READY: pa_context_get_source_info_list(pa_context, (pa_source_info_cb_t) source_info_iterator, context); break; case PA_CONTEXT_FAILED: g_warning("PulseAudio: failed to connect to daemon"); finish_pa_list(context); break; case PA_CONTEXT_TERMINATED: break; case PA_CONTEXT_UNCONNECTED: break; case PA_CONTEXT_CONNECTING: break; case PA_CONTEXT_AUTHORIZING: break; case PA_CONTEXT_SETTING_NAME: break; default: break; } }
static void simple_callback(pa_context *c, int success, void *userdata) { if (!success) { fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c))); } }
void RageSoundDriver_PulseAudio::CtxStateCb(pa_context *c) { switch (pa_context_get_state(m_PulseCtx)) { case PA_CONTEXT_CONNECTING: LOG->Trace("Pulse: Context connecting..."); break; case PA_CONTEXT_AUTHORIZING: LOG->Trace("Pulse: Context authorizing..."); break; case PA_CONTEXT_SETTING_NAME: LOG->Trace("Pulse: Context setting name..."); break; case PA_CONTEXT_READY: LOG->Trace("Pulse: Context ready now."); m_InitStream(); break; case PA_CONTEXT_TERMINATED: case PA_CONTEXT_FAILED: if(asprintf(&m_Error, "context connection failed: %s", pa_strerror(pa_context_errno(m_PulseCtx))) == -1) { m_Error = nullptr; } m_Sem.Post(); return; break; } }
static void pulse_write_preprocess(MSFilter *f){ PulseWriteState *s=(PulseWriteState*)f->data; int err; pa_sample_spec pss; pa_buffer_attr attr; if (context==NULL) return; pss.format=PA_SAMPLE_S16LE; pss.channels=s->channels; pss.rate=s->rate; s->fragsize=latency_req*(float)s->channels*(float)s->rate*2; attr.maxlength=-1; attr.tlength=s->fragsize; attr.prebuf=-1; attr.minreq=-1; attr.fragsize=-1; s->stream=pa_stream_new(context,"phone",&pss,NULL); if (s->stream==NULL){ ms_error("pa_stream_new() failed: %s",pa_strerror(pa_context_errno(context))); return; } pa_threaded_mainloop_lock(pa_loop); err=pa_stream_connect_playback(s->stream,NULL,&attr, PA_STREAM_ADJUST_LATENCY,NULL,NULL); pa_threaded_mainloop_unlock(pa_loop); if (err!=0){ ms_error("pa_stream_connect_playback() failed"); } }