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 CAESinkPULSE::UpdateInternalVolume(const pa_cvolume* nVol) { if (!nVol) return; pa_volume_t o_vol = pa_cvolume_avg(&m_Volume); pa_volume_t n_vol = pa_cvolume_avg(nVol); if (o_vol != n_vol) { pa_cvolume_set(&m_Volume, m_Channels, n_vol); m_volume_needs_update = true; } }
pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { uint64_t sum = 0; unsigned c, n; pa_assert(a); if (!cm) return pa_cvolume_avg(a); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); for (c = n = 0; c < a->channels; c++) { if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) continue; sum += a->values[c]; n ++; } if (n > 0) sum /= n; return (pa_volume_t) sum; }
char * getpavolume(void) { uint8_t ctr; char * result; pa_devicelist_t pa_output_devicelist[16]; result = smprintf("vol: "); if (pa_get_devicelist(pa_output_devicelist) < 0) { return smprintf("ERR"); } for (ctr = 0; ctr < 16; ctr++) { if (! pa_output_devicelist[ctr].initialized) { continue; } if ( pa_output_devicelist[ctr].mute ) { char * tmp_res = result ; result = smprintf("%s mute", tmp_res) ; free(tmp_res); } else { char * tmp_res = result; result = smprintf("%s %d%%", tmp_res, (pa_cvolume_avg(&pa_output_devicelist[ctr].volume)*100)/PA_VOLUME_NORM); free(tmp_res); } } return result; }
gint xvd_get_readable_volume (const pa_cvolume *vol) { guint new_vol = 0; new_vol = 100 * pa_cvolume_avg (vol) / PA_VOLUME_NORM; return MIN (new_vol, 100); }
void PulseOutput::sink_info_callback(pa_context*, const pa_sink_input_info * info,int /*eol*/,void*userdata){ PulseOutput * out = static_cast<PulseOutput*>(userdata); if (info) { pa_volume_t value = pa_cvolume_avg(&info->volume); if (out->pulsevolume!=value) { out->context->notify_volume((float)value / (float)PA_VOLUME_NORM); } } }
void pulse_get_default_sink_volume_cb(pa_context UNUSED *c, const pa_sink_info *i, int eol, void *raw) { if (eol) return; struct pulseaudio_t *pulse = (struct pulseaudio_t*)raw; pulse->muted = i->mute; pulse->cvolume = i->volume; pulse->volume = pa_cvolume_avg(&(i->volume)); }
static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SOURCE(o)->userdata; int err; audio_info_t info; switch (code) { case PA_SOURCE_MESSAGE_GET_LATENCY: { pa_usec_t r = 0; if (u->fd) { err = ioctl(u->fd, AUDIO_GETINFO, &info); pa_assert(err >= 0); r += pa_bytes_to_usec(info.record.samples * u->frame_size, &PA_SOURCE(o)->sample_spec); r -= pa_bytes_to_usec(u->read_bytes, &PA_SOURCE(o)->sample_spec); } *((pa_usec_t*) data) = r; return 0; } case PA_SOURCE_MESSAGE_SET_VOLUME: if (u->fd >= 0) { AUDIO_INITINFO(&info); info.record.gain = pa_cvolume_avg((pa_cvolume*) data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; assert(info.record.gain <= AUDIO_MAX_GAIN); if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) pa_log("AUDIO_SETINFO: Unsupported volume."); else pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); } else { return 0; } } break; case PA_SOURCE_MESSAGE_GET_VOLUME: if (u->fd >= 0) { err = ioctl(u->fd, AUDIO_GETINFO, &info); pa_assert(err >= 0); pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels, info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); return 0; } break; } return pa_source_process_msg(o, code, data, offset, chunk); }
void PulseStream::setVolume(const pa_cvolume *volume) { if (mCachedVolume != -1) QMetaObject::invokeMethod(this, "applyCachedVolume", Qt::QueuedConnection); if (pa_cvolume_equal(&mVolume, volume) == 0) { memcpy(&mVolume, volume, sizeof(mVolume)); qreal vol = (qreal)pa_cvolume_avg(volume) / PA_VOLUME_NORM; // AudioOutput expects the "backend" to supply values that have been // adjusted for Stephens' law, so we need to fudge them accordingly // so that the %ages match up in KMix/the application's own slider. emit volumeChanged(qPow(vol, VOLTAGE_TO_LOUDNESS_EXPONENT)); } }
pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) { int a, b; pa_cvolume result; pa_assert(v); pa_assert(from); pa_assert(to); pa_return_val_if_fail(pa_channel_map_valid(to), NULL); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL); if (pa_channel_map_equal(from, to)) return v; result.channels = to->channels; for (b = 0; b < to->channels; b++) { pa_volume_t k = 0; int n = 0; for (a = 0; a < from->channels; a++) if (from->map[a] == to->map[b]) { k += v->values[a]; n ++; } if (n <= 0) { for (a = 0; a < from->channels; a++) if ((on_left(from->map[a]) && on_left(to->map[b])) || (on_right(from->map[a]) && on_right(to->map[b])) || (on_center(from->map[a]) && on_center(to->map[b])) || (on_lfe(from->map[a]) && on_lfe(to->map[b]))) { k += v->values[a]; n ++; } } if (n <= 0) k = pa_cvolume_avg(v); else k /= n; result.values[b] = k; } *v = result; return v; }
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; } }
/** * @brief Callback function called when the information on the * context's sink is retrieved. * @param ctx Context which operation has succeeded * @param info Structure containing the sink's information * @param this_gen pulse_driver_t pointer for the PulseAudio output * instance. * * This function saves the volume field of the passed structure to the * @c cvolume variable of the output instance and send an update volume * event to the frontend. */ static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info *info, int is_last, void *userdata) { pulse_driver_t *const this = (pulse_driver_t *) userdata; if (is_last < 0) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to get sink input info: %s\n", pa_strerror(pa_context_errno(this->context))); return; } if (!info) return; this->cvolume = info->volume; this->swvolume = pa_cvolume_avg(&info->volume); #if PA_PROTOCOL_VERSION >= 11 /* PulseAudio 0.9.7 and newer */ this->muted = info->mute; #else this->muted = pa_cvolume_is_muted (&this->cvolume); #endif /* send update volume event to frontend */ xine_event_t event; xine_audio_level_data_t data; xine_stream_t *stream; xine_list_iterator_t ite; data.right = data.left = (int) (pa_sw_volume_to_linear(this->swvolume)*100); data.mute = this->muted; event.type = XINE_EVENT_AUDIO_LEVEL; event.data = &data; event.data_length = sizeof(data); pthread_mutex_lock(&this->xine->streams_lock); for(ite = xine_list_front(this->xine->streams); ite; ite = xine_list_next(this->xine->streams, ite)) { stream = xine_list_get_value(this->xine->streams, ite); event.stream = stream; xine_event_send(stream, &event); } pthread_mutex_unlock(&this->xine->streams_lock); }
static void pulse_get_volume (int * l, int * r) { * l = * r = 0; if (! connected || ! volume_valid) return; pa_threaded_mainloop_lock (mainloop); CHECK_DEAD_GOTO (fail, 1); if (volume.channels == 2) { * l = (volume.values[0] * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM; * r = (volume.values[1] * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM; } else * l = * r = (pa_cvolume_avg (& volume) * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM; fail: pa_threaded_mainloop_unlock (mainloop); }
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 ui_update_statusicon(menu_info_item_t* mii) { #ifdef DEBUG g_message("pulseaudio_update_status_icon(%s)", mii->name); #endif pa_volume_t volume = pa_cvolume_avg(mii->volume); g_message("volume:%u%s", volume, mii->mute ? " muted" : ""); const char* icon_name = NULL; if(volume == PA_VOLUME_MUTED || mii->mute) icon_name = "stock_volume-mute"; else if(volume < (PA_VOLUME_NORM / 3)) icon_name = "stock_volume-min"; else if(volume < (PA_VOLUME_NORM / 3 * 2)) icon_name = "stock_volume-med"; else icon_name = "stock_volume-max"; menu_infos_t* mis = mii->menu_info->menu_infos; gtk_status_icon_set_from_icon_name(mis->icon, icon_name); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; int err; audio_info_t info; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t r = 0; if (u->fd >= 0) { err = ioctl(u->fd, AUDIO_GETINFO, &info); pa_assert(err >= 0); r += pa_bytes_to_usec(u->written_bytes, &PA_SINK(o)->sample_spec); r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &PA_SINK(o)->sample_spec); if (u->memchunk.memblock) r += pa_bytes_to_usec(u->memchunk.length, &PA_SINK(o)->sample_spec); } *((pa_usec_t*) data) = r; return 0; } case PA_SINK_MESSAGE_SET_VOLUME: if (u->fd >= 0) { AUDIO_INITINFO(&info); info.play.gain = pa_cvolume_avg((pa_cvolume*)data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; assert(info.play.gain <= AUDIO_MAX_GAIN); if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) pa_log("AUDIO_SETINFO: Unsupported volume."); else pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); } else { return 0; } } break; case PA_SINK_MESSAGE_GET_VOLUME: if (u->fd >= 0) { err = ioctl(u->fd, AUDIO_GETINFO, &info); assert(err >= 0); pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); return 0; } break; case PA_SINK_MESSAGE_SET_MUTE: if (u->fd >= 0) { AUDIO_INITINFO(&info); info.output_muted = !!PA_PTR_TO_UINT(data); if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); else return 0; } break; case PA_SINK_MESSAGE_GET_MUTE: if (u->fd >= 0) { err = ioctl(u->fd, AUDIO_GETINFO, &info); pa_assert(err >= 0); *(int*)data = !!info.output_muted; return 0; } break; } return pa_sink_process_msg(o, code, data, offset, chunk); }
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; } }