static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) { PAVoiceIn *pa = (PAVoiceIn *) hw; pa_operation *op; pa_cvolume v; paaudio *g = pa->g; #ifdef PA_CHECK_VERSION pa_cvolume_init (&v); #endif switch (cmd) { case VOICE_VOLUME: { SWVoiceIn *sw; va_list ap; va_start (ap, cmd); sw = va_arg (ap, SWVoiceIn *); va_end (ap); v.channels = 2; v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; pa_threaded_mainloop_lock (g->mainloop); op = pa_context_set_source_output_volume (g->context, pa_stream_get_index (pa->stream), &v, NULL, NULL); if (!op) { qpa_logerr (pa_context_errno (g->context), "set_source_output_volume() failed\n"); } else { pa_operation_unref(op); } op = pa_context_set_source_output_mute (g->context, pa_stream_get_index (pa->stream), sw->vol.mute, NULL, NULL); if (!op) { qpa_logerr (pa_context_errno (g->context), "set_source_output_mute() failed\n"); } else { pa_operation_unref (op); } pa_threaded_mainloop_unlock (g->mainloop); } } return 0; }
static int control(int cmd, void *arg) { switch (cmd) { case AOCONTROL_GET_VOLUME: { ao_control_vol_t *vol = arg; uint32_t devidx = pa_stream_get_index(stream); pa_threaded_mainloop_lock(mainloop); if (!waitop(pa_context_get_sink_input_info(context, devidx, info_func, NULL))) { GENERIC_ERR_MSG(context, "pa_stream_get_sink_input_info() failed"); return CONTROL_ERROR; } if (volume.channels != 2) vol->left = vol->right = pa_cvolume_avg(&volume)*100/PA_VOLUME_NORM; else { vol->left = volume.values[0]*100/PA_VOLUME_NORM; vol->right = volume.values[1]*100/PA_VOLUME_NORM; } return CONTROL_OK; } case AOCONTROL_SET_VOLUME: { const ao_control_vol_t *vol = arg; pa_operation *o; if (volume.channels != 2) pa_cvolume_set(&volume, volume.channels, (pa_volume_t)vol->left*PA_VOLUME_NORM/100); else { volume.values[0] = (pa_volume_t)vol->left*PA_VOLUME_NORM/100; volume.values[1] = (pa_volume_t)vol->right*PA_VOLUME_NORM/100; } pa_threaded_mainloop_lock(mainloop); o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL); if (!o) { pa_threaded_mainloop_unlock(mainloop); GENERIC_ERR_MSG(context, "pa_context_set_sink_input_volume() failed"); return CONTROL_ERROR; } /* We don't wait for completion here */ pa_operation_unref(o); pa_threaded_mainloop_unlock(mainloop); return CONTROL_OK; } default: return CONTROL_UNKNOWN; } }
void CPulseAEStream::SetVolume(float volume) { if (!m_Initialized) return; if (!pa_threaded_mainloop_in_thread(m_MainLoop)) pa_threaded_mainloop_lock(m_MainLoop); if (volume > 0.f) { m_Volume = volume; pa_volume_t paVolume = pa_sw_volume_from_linear((double)(m_Volume * m_MaxVolume)); pa_cvolume_set(&m_ChVolume, m_SampleSpec.channels, paVolume); } else pa_cvolume_mute(&m_ChVolume,m_SampleSpec.channels); pa_operation *op = pa_context_set_sink_input_volume(m_Context, pa_stream_get_index(m_Stream), &m_ChVolume, NULL, NULL); if (op == NULL) CLog::Log(LOGERROR, "PulseAudio: Failed to set volume"); else pa_operation_unref(op); if (!pa_threaded_mainloop_in_thread(m_MainLoop)) pa_threaded_mainloop_unlock(m_MainLoop); }
int xmms_pulse_backend_volume_get (xmms_pulse *p, unsigned int *vol) { pa_operation *o; int idx; if (p == NULL) { return FALSE; } pa_threaded_mainloop_lock (p->mainloop); *vol = -1; if (p->stream != NULL) { idx = pa_stream_get_index (p->stream); o = pa_context_get_sink_input_info (p->context, idx, volume_get_cb, vol); if (o) { while (pa_operation_get_state (o) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait (p->mainloop); } pa_operation_unref (o); } } pa_threaded_mainloop_unlock (p->mainloop); return *vol != -1; }
/** * @brief Callback function called when the state of the daemon changes * @param c Context in which the state of the daemon changes * @param t Subscription event type * @param idx Index of the sink * @param this_gen pulse_driver_t pointer for the PulseAudio output * instance. */ static void __xine_pa_context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *this_gen) { pulse_driver_t * this = (pulse_driver_t*) this_gen; int index; if (this->stream == NULL) return; index = pa_stream_get_index(this->stream); if (index != idx) return; if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE) return; pa_operation *operation = pa_context_get_sink_input_info( this->context, index, __xine_pa_sink_info_callback, this); if (operation == NULL) { xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to get sink info: %s\n", pa_strerror(pa_context_errno (this->context))); return; } pa_operation_unref(operation); }
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 PulseOutput::volume(FXfloat v) { if (pulse_context && stream) { pulsevolume = (pa_volume_t)(v*PA_VOLUME_NORM); pa_cvolume cvol; pa_cvolume_set(&cvol,af.channels,pulsevolume); pa_operation* operation = pa_context_set_sink_input_volume(pulse_context,pa_stream_get_index(stream),&cvol,nullptr,nullptr); pa_operation_unref(operation); } }
/** Issue special libao controls on the device */ static int control(int cmd, void *arg) { if (!context || !stream) return CONTROL_ERROR; switch (cmd) { case AOCONTROL_SET_DEVICE: /* Change the playback device */ sink = (char*)arg; return CONTROL_OK; case AOCONTROL_GET_DEVICE: /* Return the playback device */ *(char**)arg = sink; return CONTROL_OK; case AOCONTROL_GET_VOLUME: { /* Return the current volume of the playback stream */ ao_control_vol_t *vol = (ao_control_vol_t*) arg; volume = PA_VOLUME_NORM; wait_for_operation(pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_func, NULL)); vol->left = vol->right = (int) (pa_volume_to_user(volume)*100); return CONTROL_OK; } case AOCONTROL_SET_VOLUME: { /* Set the playback volume of the stream */ const ao_control_vol_t *vol = (ao_control_vol_t*) arg; int v = vol->left; if (vol->right > v) v = vol->left; wait_for_operation(pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), pa_volume_from_user((double)v/100), NULL, NULL)); return CONTROL_OK; } default: /* Unknown CONTROL command */ return CONTROL_UNKNOWN; } }
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); if (gCoreContext->GetSetting("MixerControl", "PCM").toLower() == "pcm") { uint32_t stream_index = pa_stream_get_index(pstream); pa_threaded_mainloop_lock(mainloop); pa_operation *op = pa_context_set_sink_input_volume(pcontext, stream_index, &volume_control, OpCompletionCallback, this); pa_threaded_mainloop_unlock(mainloop); if (op) pa_operation_unref(op); else VBERROR(fn_log_tag + QString("set stream volume operation failed, stream %1, " "error %2 ") .arg(stream_index) .arg(pa_strerror(pa_context_errno(pcontext)))); } else { 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 subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { ENTER(__FUNCTION__); assert(c); if (!stream || index != pa_stream_get_index(stream) || (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) && t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW))) return; }
static void volume_time_cb(pa_mainloop_api *api, pa_time_event *e, const struct timeval *tv, void *userdata) { pa_operation *o; if (!(o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL))) AUDDBG("pa_context_set_sink_input_volume() failed: %s", pa_strerror(pa_context_errno(context))); else pa_operation_unref(o); /* We don't wait for completion of this command */ api->time_free(volume_time_event); volume_time_event = NULL; }
static void SinkInputInfoChangedCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { CAESinkPULSE* p = (CAESinkPULSE*) userdata; if (!p || !p->IsInitialized()) return; if (idx != pa_stream_get_index(p->GetInternalStream())) return; pa_operation* op = pa_context_get_sink_input_info(c, idx, SinkInputInfoCallback, p); if (op == NULL) CLog::Log(LOGERROR, "PulseAudio: Failed to sync volume"); else pa_operation_unref(op); }
int pa_simple_set_volume(pa_simple *p, int volume, int *rerror) { pa_operation *o = NULL; pa_stream *s = NULL; uint32_t idx; pa_cvolume cv; pa_volume_t v; pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); CHECK_VALIDITY_RETURN_ANY(rerror, volume >= 0, PA_ERR_INVALID, -1); CHECK_VALIDITY_RETURN_ANY(rerror, volume <= 65535, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); CHECK_SUCCESS_GOTO(p, rerror, ((idx = pa_stream_get_index (p->stream)) != PA_INVALID_INDEX), unlock_and_fail); s = p->stream; pa_assert(s); pa_cvolume_set(&cv, s->sample_spec.channels, volume); o = pa_context_set_sink_input_volume (p->context, idx, &cv, success_context_cb, p); CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); p->operation_success = 0; while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); pa_operation_unref(o); pa_threaded_mainloop_unlock(p->mainloop); return 0; unlock_and_fail: if (o) { pa_operation_cancel(o); pa_operation_unref(o); } pa_threaded_mainloop_unlock(p->mainloop); return -1; }
int pa_simple_get_stream_index(pa_simple *p, unsigned int *idx, int *rerror) { pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, idx != NULL, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); *idx = pa_stream_get_index(p->stream); pa_threaded_mainloop_unlock(p->mainloop); return 0; unlock_and_fail: pa_threaded_mainloop_unlock(p->mainloop); return -1; }
static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { pa_operation *o; assert(c); if (!stream || index != pa_stream_get_index(stream) || (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) && t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW))) return; if (!(o = pa_context_get_sink_input_info(c, index, info_cb, NULL))) { AUDDBG("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(c))); return; } pa_operation_unref(o); }
/** * Mute (from within showtime), send update to PA * * Lock for PA mainloop is already held */ static void set_mastermute(void *opaque, int value) { pa_audio_mode_t *pam = opaque; pa_operation *o; pam->muted = value; if(pam->stream == NULL || pa_stream_get_state(pam->stream) != PA_STREAM_READY) return; o = pa_context_set_sink_input_mute(pam->context, pa_stream_get_index(pam->stream), pam->muted, NULL, NULL); if(o != NULL) pa_operation_unref(o); }
void PulseOutput::context_subscribe_callback(pa_context * pulse_context, pa_subscription_event_type_t type, uint32_t index, void *userdata){ PulseOutput * out = static_cast<PulseOutput*>(userdata); if (out->stream==nullptr) return; if (pa_stream_get_index(out->stream)!=index) return; if ((type&PA_SUBSCRIPTION_EVENT_FACILITY_MASK)!=PA_SUBSCRIPTION_EVENT_SINK_INPUT) return; if ((type&PA_SUBSCRIPTION_EVENT_TYPE_MASK)==PA_SUBSCRIPTION_EVENT_CHANGE || (type&PA_SUBSCRIPTION_EVENT_TYPE_MASK)==PA_SUBSCRIPTION_EVENT_NEW) { pa_operation *operation = pa_context_get_sink_input_info(pulse_context,index,sink_info_callback,userdata); if (operation) pa_operation_unref(operation); } }
static void pulse_output_subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct pulse_output *po = userdata; pa_subscription_event_type_t facility = t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK; pa_subscription_event_type_t type = t & PA_SUBSCRIPTION_EVENT_TYPE_MASK; if (po->mixer != NULL && facility == PA_SUBSCRIPTION_EVENT_SINK_INPUT && po->stream != NULL && pa_stream_get_state(po->stream) == PA_STREAM_READY && idx == pa_stream_get_index(po->stream) && (type == PA_SUBSCRIPTION_EVENT_NEW || type == PA_SUBSCRIPTION_EVENT_CHANGE)) pulse_mixer_on_change(po->mixer, context, po->stream); }
int xmms_pulse_backend_volume_set (xmms_pulse *p, unsigned int vol) { pa_operation *o; pa_cvolume cvol; int idx, res = 0; if (p == NULL) { return FALSE; } pa_threaded_mainloop_lock (p->mainloop); if (p->stream != NULL) { pa_cvolume_set (&cvol, p->sample_spec.channels, PA_VOLUME_NORM * vol / 100); idx = pa_stream_get_index (p->stream); o = pa_context_set_sink_input_volume (p->context, idx, &cvol, volume_set_cb, &res); if (o) { /* wait for result to land */ while (pa_operation_get_state (o) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait (p->mainloop); } pa_operation_unref (o); /* The cb set res to 1 or 0 depending on success */ if (res) { p->volume = vol; } } } pa_threaded_mainloop_unlock (p->mainloop); return res; }
/** * Volume adjusted (from within showtime), send update to PA * * Lock for PA mainloop is already held */ static void set_mastervol(void *opaque, float value) { pa_audio_mode_t *pam = opaque; pa_operation *o; pa_cvolume cv; pam->mastervol = pa_sw_volume_from_dB(value); if(pam->stream == NULL || pa_stream_get_state(pam->stream) != PA_STREAM_READY) return; memset(&cv, 0, sizeof(cv)); pa_cvolume_set(&cv, pam->ss.channels, pam->mastervol); o = pa_context_set_sink_input_volume(pam->context, pa_stream_get_index(pam->stream), &cv, NULL, NULL); if(o != NULL) pa_operation_unref(o); }
static void stream_state_callback(pa_stream *s, void *userdata) { pa_audio_mode_t *pam = (pa_audio_mode_t *)userdata; pa_operation *o; if(pa_stream_get_state(s) == PA_STREAM_FAILED) { pam->stream_error = pa_context_errno(pam->context); TRACE(TRACE_ERROR, "PA", "Stream failure: %s", pa_strerror(pam->stream_error)); } if(pa_stream_get_state(s) == PA_STREAM_READY && pam->muted) { o = pa_context_set_sink_input_mute(pam->context, pa_stream_get_index(pam->stream), pam->muted, NULL, NULL); if(o != NULL) pa_operation_unref(o); } pa_threaded_mainloop_signal(mainloop, 0); }
static void subscription_event_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { pa_audio_mode_t *pam = (pa_audio_mode_t *)userdata; pa_operation *o; if(pam->stream == NULL || pa_stream_get_state(pam->stream) != PA_STREAM_READY) return; if((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) != PA_SUBSCRIPTION_EVENT_SINK_INPUT) return; if(pa_stream_get_index(pam->stream) != idx) return; o = pa_context_get_sink_input_info(pam->context, idx, update_sink_input_info, pam); if(o != NULL) pa_operation_unref(o); }
void CAESinkPULSE::SetVolume(float volume) { if (m_IsAllocated && !m_passthrough) { pa_threaded_mainloop_lock(m_MainLoop); // clamp possibly too large / low values float per_cent_volume = std::max(0.0f, std::min(volume, 1.0f)); if (m_volume_needs_update) { m_volume_needs_update = false; pa_volume_t n_vol = pa_cvolume_avg(&m_Volume); n_vol = std::min(n_vol, PA_VOLUME_NORM); per_cent_volume = (float) n_vol / PA_VOLUME_NORM; // only update internal volume pa_threaded_mainloop_unlock(m_MainLoop); g_application.SetVolume(per_cent_volume, false); return; } pa_volume_t pavolume = per_cent_volume * PA_VOLUME_NORM; unsigned int sink_input_idx = pa_stream_get_index(m_Stream); if ( pavolume <= 0 ) pa_cvolume_mute(&m_Volume, m_Channels); else pa_cvolume_set(&m_Volume, m_Channels, pavolume); pa_operation *op = pa_context_set_sink_input_volume(m_Context, sink_input_idx, &m_Volume, NULL, NULL); if (op == NULL) CLog::Log(LOGERROR, "PulseAudio: Failed to set volume"); else pa_operation_unref(op); pa_threaded_mainloop_unlock(m_MainLoop); } }
/*** Context ***/ static void context_cb(pa_context *ctx, pa_subscription_event_type_t type, uint32_t idx, void *userdata) { audio_output_t *aout = userdata; aout_sys_t *sys = aout->sys; unsigned facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK; type &= PA_SUBSCRIPTION_EVENT_TYPE_MASK; switch (facility) { case PA_SUBSCRIPTION_EVENT_SINK: sink_event(ctx, type, idx, userdata); break; case PA_SUBSCRIPTION_EVENT_SINK_INPUT: /* only interested in our sink input */ if (sys->stream != NULL && idx == pa_stream_get_index(sys->stream)) sink_input_event(ctx, type, idx, userdata); break; default: /* unsubscribed facility?! */ assert(0); } }
void AudioStream::moved(pa_stream* s) { audiostream_ = s; RING_DBG("Stream %d to %s", pa_stream_get_index(s), pa_stream_get_device_name(s)); }
static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { pa_buffer_attr wanted; const pa_buffer_attr *actual; GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_stream_flags_t flags; pa_operation *o; GstAudioClock *clock; pa_threaded_mainloop_lock (pulsesrc->mainloop); { GstAudioRingBufferSpec s = *spec; const pa_channel_map *m; m = pa_stream_get_channel_map (pulsesrc->stream); gst_pulse_channel_map_to_gst (m, &s); gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC (pulsesrc)->ringbuffer, s.info.position); } /* enable event notifications */ GST_LOG_OBJECT (pulsesrc, "subscribing to context events"); if (!(o = pa_context_subscribe (pulsesrc->context, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, NULL))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_context_subscribe() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } pa_operation_unref (o); wanted.maxlength = -1; wanted.tlength = -1; wanted.prebuf = 0; wanted.minreq = -1; wanted.fragsize = spec->segsize; GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d", wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", wanted.prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d", wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d", wanted.fragsize); flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED; if (pulsesrc->mute_set && pulsesrc->mute) flags |= PA_STREAM_START_MUTED; if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted, flags) < 0) { goto connect_failed; } /* our clock will now start from 0 again */ clock = GST_AUDIO_CLOCK (GST_AUDIO_BASE_SRC (pulsesrc)->clock); gst_audio_clock_reset (clock, 0); pulsesrc->corked = TRUE; for (;;) { pa_stream_state_t state; state = pa_stream_get_state (pulsesrc->stream); if (!PA_STREAM_IS_GOOD (state)) goto stream_is_bad; if (state == PA_STREAM_READY) break; /* Wait until the stream is ready */ pa_threaded_mainloop_wait (pulsesrc->mainloop); } pulsesrc->stream_connected = TRUE; /* store the source output index so it can be accessed via a property */ pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream); g_object_notify (G_OBJECT (pulsesrc), "source-output-index"); if (pulsesrc->volume_set) { gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume); pulsesrc->volume_set = FALSE; } /* get the actual buffering properties now */ actual = pa_stream_get_buffer_attr (pulsesrc->stream); GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d (wanted: %d)", actual->tlength, wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", actual->prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d (wanted %d)", actual->minreq, wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d (wanted %d)", actual->fragsize, wanted.fragsize); if (actual->fragsize >= wanted.fragsize) { spec->segsize = actual->fragsize; } else { spec->segsize = actual->fragsize * (wanted.fragsize / actual->fragsize); } spec->segtotal = actual->maxlength / spec->segsize; if (!pulsesrc->paused) { GST_DEBUG_OBJECT (pulsesrc, "uncorking because we are playing"); gst_pulsesrc_set_corked (pulsesrc, FALSE, FALSE); } pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; /* ERRORS */ connect_failed: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } stream_is_bad: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } unlock_and_fail: { gst_pulsesrc_destroy_stream (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return FALSE; } }
static int control(struct ao *ao, enum aocontrol cmd, void *arg) { struct priv *priv = ao->priv; switch (cmd) { case AOCONTROL_GET_MUTE: case AOCONTROL_GET_VOLUME: { uint32_t devidx = pa_stream_get_index(priv->stream); pa_threaded_mainloop_lock(priv->mainloop); if (!waitop(priv, pa_context_get_sink_input_info(priv->context, devidx, info_func, ao))) { GENERIC_ERR_MSG(priv->context, "pa_stream_get_sink_input_info() failed"); return CONTROL_ERROR; } // Warning: some information in pi might be unaccessible, because // we naively copied the struct, without updating pointers etc. // Pointers might point to invalid data, accessors might fail. if (cmd == AOCONTROL_GET_VOLUME) { ao_control_vol_t *vol = arg; if (priv->pi.volume.channels != 2) vol->left = vol->right = pa_cvolume_avg(&priv->pi.volume) * 100 / PA_VOLUME_NORM; else { vol->left = priv->pi.volume.values[0] * 100 / PA_VOLUME_NORM; vol->right = priv->pi.volume.values[1] * 100 / PA_VOLUME_NORM; } } else if (cmd == AOCONTROL_GET_MUTE) { bool *mute = arg; *mute = priv->pi.mute; } return CONTROL_OK; } case AOCONTROL_SET_MUTE: case AOCONTROL_SET_VOLUME: { pa_operation *o; pa_threaded_mainloop_lock(priv->mainloop); uint32_t stream_index = pa_stream_get_index(priv->stream); if (cmd == AOCONTROL_SET_VOLUME) { const ao_control_vol_t *vol = arg; struct pa_cvolume volume; pa_cvolume_reset(&volume, ao->channels); if (volume.channels != 2) pa_cvolume_set(&volume, volume.channels, vol->left * PA_VOLUME_NORM / 100); else { volume.values[0] = vol->left * PA_VOLUME_NORM / 100; volume.values[1] = vol->right * PA_VOLUME_NORM / 100; } o = pa_context_set_sink_input_volume(priv->context, stream_index, &volume, NULL, NULL); if (!o) { pa_threaded_mainloop_unlock(priv->mainloop); GENERIC_ERR_MSG(priv->context, "pa_context_set_sink_input_volume() failed"); return CONTROL_ERROR; } } else if (cmd == AOCONTROL_SET_MUTE) { const bool *mute = arg; o = pa_context_set_sink_input_mute(priv->context, stream_index, *mute, NULL, NULL); if (!o) { pa_threaded_mainloop_unlock(priv->mainloop); GENERIC_ERR_MSG(priv->context, "pa_context_set_sink_input_mute() failed"); return CONTROL_ERROR; } } else abort(); /* We don't wait for completion here */ pa_operation_unref(o); pa_threaded_mainloop_unlock(priv->mainloop); return CONTROL_OK; } default: return CONTROL_UNKNOWN; } }
JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_pulseaudio_PA_stream_1get_1index (JNIEnv *env, jclass clazz, jlong s) { return pa_stream_get_index((pa_stream *) (intptr_t) s); }
static int pulse_open(int fmt, int rate, int nch) { pa_sample_spec ss; pa_operation *o = NULL; int success; assert(!mainloop); assert(!context); assert(!stream); assert(!connected); switch(fmt) { case FMT_U8: ss.format = PA_SAMPLE_U8; break; case FMT_S16_LE: ss.format = PA_SAMPLE_S16LE; break; case FMT_S16_BE: ss.format = PA_SAMPLE_S16BE; break; #ifdef PA_SAMPLE_S24_32LE case FMT_S24_LE: ss.format = PA_SAMPLE_S24_32LE; break; case FMT_S24_BE: ss.format = PA_SAMPLE_S24_32BE; break; #endif #ifdef PA_SAMPLE_S32LE case FMT_S32_LE: ss.format = PA_SAMPLE_S32LE; break; case FMT_S32_BE: ss.format = PA_SAMPLE_S32BE; break; #endif case FMT_FLOAT: ss.format = PA_SAMPLE_FLOAT32NE; break; default: return FALSE; } ss.rate = rate; ss.channels = nch; if (!pa_sample_spec_valid(&ss)) return FALSE; if (!(mainloop = pa_threaded_mainloop_new())) { ERROR ("Failed to allocate main loop"); goto fail; } pa_threaded_mainloop_lock(mainloop); if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Audacious"))) { ERROR ("Failed to allocate context"); goto unlock_and_fail; } pa_context_set_state_callback(context, context_state_cb, NULL); pa_context_set_subscribe_callback(context, subscribe_cb, NULL); if (pa_context_connect(context, NULL, 0, NULL) < 0) { ERROR ("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } if (pa_threaded_mainloop_start(mainloop) < 0) { ERROR ("Failed to start main loop"); goto unlock_and_fail; } /* Wait until the context is ready */ pa_threaded_mainloop_wait(mainloop); if (pa_context_get_state(context) != PA_CONTEXT_READY) { ERROR ("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } if (!(stream = pa_stream_new(context, "Audacious", &ss, NULL))) { ERROR ("Failed to create stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_stream_set_state_callback(stream, stream_state_cb, NULL); pa_stream_set_write_callback(stream, stream_request_cb, NULL); pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL); /* Connect stream with sink and default volume */ /* Buffer struct */ int aud_buffer = aud_get_int(NULL, "output_buffer_size"); size_t buffer_size = pa_usec_to_bytes(aud_buffer, &ss) * 1000; pa_buffer_attr buffer = {(uint32_t) -1, buffer_size, (uint32_t) -1, (uint32_t) -1, buffer_size}; if (pa_stream_connect_playback(stream, NULL, &buffer, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { ERROR ("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } /* Wait until the stream is ready */ pa_threaded_mainloop_wait(mainloop); if (pa_stream_get_state(stream) != PA_STREAM_READY) { ERROR ("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } /* Now subscribe to events */ if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) { ERROR ("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CHECK_DEAD_GOTO(fail, 1); pa_threaded_mainloop_wait(mainloop); } if (!success) { ERROR ("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_operation_unref(o); /* Now request the initial stream info */ if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_cb, NULL))) { ERROR ("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CHECK_DEAD_GOTO(fail, 1); pa_threaded_mainloop_wait(mainloop); } if (!volume_valid) { ERROR ("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_operation_unref(o); do_trigger = 0; written = 0; flush_time = 0; bytes_per_second = FMT_SIZEOF (fmt) * nch * rate; connected = 1; volume_time_event = NULL; pa_threaded_mainloop_unlock(mainloop); return TRUE; unlock_and_fail: if (o) pa_operation_unref(o); pa_threaded_mainloop_unlock(mainloop); fail: pulse_close(); return FALSE; }
FXbool PulseOutput::configure(const AudioFormat & fmt){ const pa_sample_spec * config=nullptr; pa_operation *operation=nullptr; if (!open()) return false; if (stream && fmt==af) return true; if (stream) { pa_stream_disconnect(stream); pa_stream_unref(stream); stream=nullptr; } pa_sample_spec spec; pa_channel_map cmap; if (!to_pulse_format(fmt,spec.format)) goto failed; spec.rate = fmt.rate; spec.channels = fmt.channels; // setup channel map pa_channel_map_init(&cmap); cmap.channels = fmt.channels; for (FXint i=0;i<fmt.channels;i++) { switch(fmt.channeltype(i)) { case Channel::None : cmap.map[i] = PA_CHANNEL_POSITION_INVALID; break; case Channel::Mono : cmap.map[i] = PA_CHANNEL_POSITION_MONO; break; case Channel::FrontLeft : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_LEFT; break; case Channel::FrontRight : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_RIGHT; break; case Channel::FrontCenter : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_CENTER; break; case Channel::BackLeft : cmap.map[i] = PA_CHANNEL_POSITION_REAR_LEFT; break; case Channel::BackRight : cmap.map[i] = PA_CHANNEL_POSITION_REAR_RIGHT; break; case Channel::BackCenter : cmap.map[i] = PA_CHANNEL_POSITION_REAR_CENTER; break; case Channel::SideLeft : cmap.map[i] = PA_CHANNEL_POSITION_SIDE_LEFT; break; case Channel::SideRight : cmap.map[i] = PA_CHANNEL_POSITION_SIDE_RIGHT; break; case Channel::LFE : cmap.map[i] = PA_CHANNEL_POSITION_LFE; break; default: goto failed; } } stream = pa_stream_new(pulse_context,"Goggles Music Manager",&spec,&cmap); if (stream == nullptr) goto failed; #ifdef DEBUG pa_stream_set_state_callback(stream,stream_state_callback,this); #endif //pa_stream_set_write_callback(stream,stream_write_callback,this); if (pa_stream_connect_playback(stream,nullptr,nullptr,PA_STREAM_NOFLAGS,nullptr,nullptr)<0) goto failed; /// Wait until stream is ready pa_stream_state_t state; while((state=pa_stream_get_state(stream))!=PA_STREAM_READY) { if (state==PA_STREAM_FAILED || state==PA_STREAM_TERMINATED){ goto failed; } context->wait_plugin_events(); } /// Get Actual Format config = pa_stream_get_sample_spec(stream); if (!to_gap_format(config->format,af)) goto failed; af.channels=config->channels; af.rate=config->rate; af.channelmap=fmt.channelmap; /// Get Current Volume operation = pa_context_get_sink_input_info(pulse_context,pa_stream_get_index(stream),sink_info_callback,this); if (operation) pa_operation_unref(operation); return true; failed: GM_DEBUG_PRINT("[pulse] Unsupported pulse configuration:\n"); fmt.debug(); return false; }