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 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); }
void change_sel_vol(pa_context * c, vol_change_t vol_change) { view_entry_t view_entry = view_selected_item(); if(view_entry.type == VIEW_SINK) { sink_t * sink = (sink_t *) view_entry.ref; if(sink != NULL) { /* averge all channel volumes of local copy */ pa_volume_t vol; vol = pa_cvolume_avg(&sink->volume); vol = modify_volume(vol, vol_change); pa_cvolume_set(&sink->volume, sink->volume.channels, vol); pa_context_set_sink_volume_by_index(c, sink->index, &sink->volume, NULL, NULL); } } if(view_entry.type == VIEW_SINK_INPUT) { sink_input_t * sink_input = (sink_input_t *) view_entry.ref; if(sink_input != NULL) { /* averge all channel volumes of local copy */ pa_volume_t vol; vol = pa_cvolume_avg(&sink_input->volume); vol = modify_volume(vol, vol_change); pa_cvolume_set(&sink_input->volume, sink_input->volume.channels, vol); pa_context_set_sink_input_volume(c, sink_input->index, &sink_input->volume, NULL, NULL); } } }
void SinkInput::setVolume(pa_cvolume v) { pa_operation *o; this->d->svolume = v; o = pa_context_set_sink_input_volume(d->context->cObject(), d->index, &d->svolume, SinkInput::volume_cb, this); pa_operation_unref(o); }
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); } }
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 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 int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) { PAVoiceOut *pa = (PAVoiceOut *) hw; pa_operation *op; pa_cvolume v; paaudio *g = pa->g; #ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */ pa_cvolume_init (&v); /* function is present in 0.9.13+ */ #endif switch (cmd) { case VOICE_VOLUME: { SWVoiceOut *sw; va_list ap; va_start (ap, cmd); sw = va_arg (ap, SWVoiceOut *); 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_sink_input_volume (g->context, pa_stream_get_index (pa->stream), &v, NULL, NULL); if (!op) qpa_logerr (pa_context_errno (g->context), "set_sink_input_volume() failed\n"); else pa_operation_unref (op); op = pa_context_set_sink_input_mute (g->context, pa_stream_get_index (pa->stream), sw->vol.mute, NULL, NULL); if (!op) { qpa_logerr (pa_context_errno (g->context), "set_sink_input_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 pulseaudio_volume(menu_info_item_t* mii, int inc) { g_debug("pulseaudio_volume(%s, %i)", mii->name, inc); /* increment/decrement in 2% steps */ pa_cvolume* volume; if(inc < 0) volume = pa_cvolume_dec(mii->volume, -inc * PA_VOLUME_NORM / 50); else if(inc > 0) { int volume_max = mii->menu_info->menu_infos->settings.volume_max; if(volume_max > 0) volume = pa_cvolume_inc_clamp(mii->volume, inc * PA_VOLUME_NORM / 50, PA_VOLUME_NORM * volume_max / 100); else volume = pa_cvolume_inc(mii->volume, inc * PA_VOLUME_NORM / 50); } else return; pa_operation* o = NULL; switch(mii->menu_info->type) { case MENU_SERVER: case MENU_MODULE: /* nothing to do here */ break; case MENU_SINK: o = pa_context_set_sink_volume_by_index(context, mii->index, volume, pulseaudio_set_volume_success_cb, mii); break; case MENU_SOURCE: o = pa_context_set_source_volume_by_index(context, mii->index, volume, pulseaudio_set_volume_success_cb, mii); break; case MENU_INPUT: o = pa_context_set_sink_input_volume(context, mii->index, volume, pulseaudio_set_volume_success_cb, mii); break; case MENU_OUTPUT: o = pa_context_set_source_output_volume(context, mii->index, volume, pulseaudio_set_volume_success_cb, mii); break; } if(o) pa_operation_unref(o); }
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; }
JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_pulseaudio_PA_context_1set_1sink_1input_1volume (JNIEnv *env, jclass clazz, jlong c, jint idx, jlong volume, jobject cb) { pa_context *c_ = (pa_context *) (intptr_t) c; uint32_t idx_ = (uint32_t) idx; return (intptr_t) pa_context_set_sink_input_volume( c_, idx_, (const pa_cvolume *) (intptr_t) volume, NULL, NULL); }
/** 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 PulseAudioSystem::volume_sink_input_list_callback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) { PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata); if (eol == 0) { // If we're using the default of "enable attenuation on all ouputs" and output from an application is loopbacked, // both the loopback and the application will be attenuated leading to double attenuation. if (!g.s.bOnlyAttenuateSameOutput && pas->iSinkId > -1 && !strcmp(i->driver, "module-loopback.c")) { return; } // If we're not attenuating different sinks and the input is not on this sink, don't attenuate. Or, // if the input is a loopback module and connected to Mumble's sink, also ignore it (loopbacks are used to connect // sinks). An attenuated loopback means an indirect application attenuation. if (g.s.bOnlyAttenuateSameOutput && pas->iSinkId > -1) { if (int(i->sink) != pas->iSinkId || (int(i->sink) == pas->iSinkId && !strcmp(i->driver, "module-loopback.c") && !g.s.bAttenuateLoopbacks)) { return; } } // ensure we're not attenuating ourselves! if (strcmp(i->name, mumble_sink_input) != 0) { // create a new entry PulseAttenuation patt; patt.index = i->index; patt.name = QLatin1String(i->name); patt.stream_restore_id = QLatin1String(pa_proplist_gets(i->proplist, "module-stream-restore.id")); patt.normal_volume = i->volume; // calculate the attenuated volume pa_volume_t adj = static_cast<pa_volume_t>(PA_VOLUME_NORM * g.s.fOtherVolume); pa_sw_cvolume_multiply_scalar(&patt.attenuated_volume, &i->volume, adj); // set it on the sink input pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &patt.attenuated_volume, NULL, NULL)); // store it pas->qhVolumes[i->index] = patt; } } else if (eol < 0) { qWarning("PulseAudio: Sink input introspection error."); } }
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); }
void backend_volume_setall(context_t *c, backend_entry_type type, uint32_t idx, int *v, int chnum) { pa_cvolume volume; volume.channels = chnum; for(int i = 0; i < chnum; ++i) { volume.values[i] = v[i]; } switch(type) { case SINK: pa_context_set_sink_volume_by_index(c->context, idx, &volume, NULL, NULL); break; case SINK_INPUT: pa_context_set_sink_input_volume(c->context, idx, &volume, NULL, NULL); break; case SOURCE: pa_context_set_source_volume_by_index(c->context, idx, &volume, NULL, NULL); break; case SOURCE_OUTPUT: pa_context_set_source_output_volume(c->context, idx, &volume, NULL, NULL); break; default: break; } }
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); } }
void PulseAudioSystem::restore_sink_input_list_callback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata) { PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata); if (eol == 0) { // if we were tracking this specific sink previously if (pas->qhVolumes.contains(i->index)) { // and if it has the attenuated volume we applied to it if (pa_cvolume_equal(&i->volume, &pas->qhVolumes[i->index].attenuated_volume) != 0) { // mark it as matched pas->qlMatchedSinks.append(i->index); // reset the volume to normal pas->iRemainingOperations++; pa_operation_unref(pa_context_set_sink_input_volume(c, i->index, &pas->qhVolumes[i->index].normal_volume, restore_volume_success_callback, pas)); } // otherwise, save for matching at the end of iteration } else { QString restore_id = QLatin1String(pa_proplist_gets(i->proplist, "module-stream-restore.id")); PulseAttenuation patt; patt.index = i->index; patt.normal_volume = i->volume; pas->qhUnmatchedSinks[restore_id] = patt; } } else if (eol < 0) { qWarning("PulseAudio: Sink input introspection error."); } else { // build a list of missing streams by iterating our active list QHash<uint32_t, PulseAttenuation>::const_iterator it; for (it = pas->qhVolumes.constBegin(); it != pas->qhVolumes.constEnd(); ++it) { // skip if previously matched if (pas->qlMatchedSinks.contains(it.key())) { continue; } // check if the restore id matches. the only case where this would // happen is if the application was reopened during attenuation. if (pas->qhUnmatchedSinks.contains(it.value().stream_restore_id)) { PulseAttenuation active_sink = pas->qhUnmatchedSinks[it.value().stream_restore_id]; // if the volume wasn't changed from our attenuation if (pa_cvolume_equal(&active_sink.normal_volume, &it.value().attenuated_volume) != 0) { // reset the volume to normal pas->iRemainingOperations++; pa_operation_unref(pa_context_set_sink_input_volume(c, active_sink.index, &it.value().normal_volume, restore_volume_success_callback, pas)); } continue; } // at this point, we don't know what happened to the sink. add // it to a list to check the stream restore database for. pas->qhMissingSinks[it.value().stream_restore_id] = it.value(); } // clean up pas->qlMatchedSinks.clear(); pas->qhUnmatchedSinks.clear(); pas->qhVolumes.clear(); // if we had missing sinks, check the stream restore database // to see if we can find and update them. if (pas->qhMissingSinks.count() > 0) { pas->iRemainingOperations++; pa_operation_unref(pa_ext_stream_restore_read(c, stream_restore_read_callback, pas)); } // trigger the volume completion callback; // necessary so that shutdown actions are called restore_volume_success_callback(c, 1, pas); } }
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; } }