pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */ return (pa_volume_t) PA_CLAMP_VOLUME((((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM)); }
pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); if (b <= PA_VOLUME_MUTED) return 0; return (pa_volume_t) (((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b); }
double pa_sw_volume_to_dB(pa_volume_t v) { pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), PA_DECIBEL_MININFTY); if (v <= PA_VOLUME_MUTED) return PA_DECIBEL_MININFTY; return linear_to_dB(pa_sw_volume_to_linear(v)); }
int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { unsigned c; pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), 0); pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0); for (c = 0; c < a->channels; c++) if (a->values[c] != v) return 0; return 1; }
int pa_cvolume_valid(const pa_cvolume *v) { unsigned c; pa_assert(v); if (!pa_channels_valid(v->channels)) return 0; for (c = 0; c < v->channels; c++) if (!PA_VOLUME_IS_VALID(v->values[c])) return 0; return 1; }
int pa_cvolume_valid(const pa_cvolume *v) { unsigned c; pa_assert(v); if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) return 0; for (c = 0; c < v->channels; c++) if (!PA_VOLUME_IS_VALID(v->values[c])) return 0; return 1; }
char *pa_volume_snprint(char *s, size_t l, pa_volume_t v) { pa_assert(s); pa_assert(l > 0); pa_init_i18n(); if (!PA_VOLUME_IS_VALID(v)) { pa_snprintf(s, l, _("(invalid)")); return s; } pa_snprintf(s, l, "%3u%%", (v*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM); return s; }
/*** Sink input ***/ static void sink_input_info_cb(pa_context *ctx, const pa_sink_input_info *i, int eol, void *userdata) { audio_output_t *aout = userdata; aout_sys_t *sys = aout->sys; if (eol) return; (void) ctx; sys->cvolume = i->volume; /* cache volume for balance preservation */ if (PA_VOLUME_IS_VALID(sys->base_volume)) VolumeReport(aout); aout_MuteReport(aout, i->mute); }
double pa_sw_volume_to_linear(pa_volume_t v) { double f; pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0.0); if (v <= PA_VOLUME_MUTED) return 0.0; if (v == PA_VOLUME_NORM) return 1.0; f = ((double) v / PA_VOLUME_NORM); return f*f*f; }
pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { unsigned i; pa_assert(dest); pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL); for (i = 0; i < a->channels; i++) dest->values[i] = pa_sw_volume_divide(a->values[i], b); dest->channels = (uint8_t) i; return dest; }
pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { pa_volume_t m; pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(dec), NULL); m = pa_cvolume_max(v); if (m <= PA_VOLUME_MUTED + dec) m = PA_VOLUME_MUTED; else m -= dec; return pa_cvolume_scale(v, m); }
pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) { pa_volume_t m; pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(inc), NULL); m = pa_cvolume_max(v); if (m >= limit - inc) m = limit; else m += inc; return pa_cvolume_scale(v, m); }
char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) { double f; pa_assert(s); pa_assert(l > 0); pa_init_i18n(); if (!PA_VOLUME_IS_VALID(v)) { pa_snprintf(s, l, _("(invalid)")); return s; } f = pa_sw_volume_to_dB(v); pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); return s; }
pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { unsigned c; pa_volume_t t = 0; pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); t = pa_cvolume_max(v); if (t <= PA_VOLUME_MUTED) return pa_cvolume_set(v, v->channels, max); for (c = 0; c < v->channels; c++) v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); return v; }
int main(int argc, char* argv[]) { // Two required arguments: // - source name (ex: alsa_input.pci-0000_00_1b.0.analog-stereo) // - target percentage volume (ex: 10) pa_volume_t volume = (pa_volume_t) (atoi(argv[2]) * (double) PA_VOLUME_NORM / 100); if (!PA_VOLUME_IS_VALID(volume)) { return 3; } char* source_name = pa_xstrdup(argv[1]); signal(SIGINT, set_terminate); signal(SIGTERM, set_terminate); int retcode = force_volume(source_name, volume); pa_xfree(source_name); return retcode; }
pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_proplist *p, pa_context_play_sample_cb_t cb, void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; pa_assert(c); pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED); o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); if (!dev) dev = c->conf->default_sink; t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag); pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); if (!PA_VOLUME_IS_VALID(volume) && c->version < 15) volume = PA_VOLUME_NORM; pa_tagstruct_putu32(t, volume); pa_tagstruct_puts(t, name); if (p) pa_tagstruct_put_proplist(t, p); else { p = pa_proplist_new(); pa_tagstruct_put_proplist(t, p); pa_proplist_free(p); } pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, play_sample_with_proplist_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); return o; }
char *pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB) { char dB[PA_SW_VOLUME_SNPRINT_DB_MAX]; pa_assert(s); pa_assert(l > 0); pa_init_i18n(); if (!PA_VOLUME_IS_VALID(v)) { pa_snprintf(s, l, _("(invalid)")); return s; } pa_snprintf(s, l, "%" PRIu32 " / %3u%%%s%s", v, (v * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM, print_dB ? " / " : "", print_dB ? pa_sw_volume_snprint_dB(dB, sizeof(dB), v) : ""); return s; }
pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask) { unsigned c; pa_volume_t t = 0; pa_assert(v); pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); if (!cm) return pa_cvolume_scale(v, max); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL); t = pa_cvolume_max_mask(v, cm, mask); if (t <= PA_VOLUME_MUTED) return pa_cvolume_set(v, v->channels, max); for (c = 0; c < v->channels; c++) v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); return v; }
pa_cvolume* pa_cvolume_set_position( pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t, pa_volume_t v) { unsigned c; pa_bool_t good = FALSE; pa_assert(cv); pa_assert(map); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL); pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), NULL); for (c = 0; c < map->channels; c++) if (map->map[c] == t) { cv->values[c] = v; good = TRUE; } return good ? cv : NULL; }
int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume, pa_proplist *p, uint32_t *sink_input_idx) { pa_scache_entry *e; pa_cvolume r; pa_proplist *merged; pa_bool_t pass_volume; pa_assert(c); pa_assert(name); pa_assert(sink); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE))) return -1; merged = pa_proplist_new(); pa_proplist_sets(merged, PA_PROP_MEDIA_NAME, name); pa_proplist_sets(merged, PA_PROP_EVENT_ID, name); if (e->lazy && !e->memchunk.memblock) { pa_channel_map old_channel_map = e->channel_map; if (pa_sound_file_load(c->mempool, e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, merged) < 0) goto fail; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); if (e->volume_is_set) { if (pa_cvolume_valid(&e->volume)) pa_cvolume_remap(&e->volume, &old_channel_map, &e->channel_map); else pa_cvolume_reset(&e->volume, e->sample_spec.channels); } } if (!e->memchunk.memblock) goto fail; pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name); pass_volume = TRUE; if (e->volume_is_set && PA_VOLUME_IS_VALID(volume)) { pa_cvolume_set(&r, e->sample_spec.channels, volume); pa_sw_cvolume_multiply(&r, &r, &e->volume); } else if (e->volume_is_set) r = e->volume; else if (PA_VOLUME_IS_VALID(volume)) pa_cvolume_set(&r, e->sample_spec.channels, volume); else pass_volume = FALSE; pa_proplist_update(merged, PA_UPDATE_REPLACE, e->proplist); if (p) pa_proplist_update(merged, PA_UPDATE_REPLACE, p); if (pa_play_memchunk(sink, &e->sample_spec, &e->channel_map, &e->memchunk, pass_volume ? &r : NULL, merged, PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND, sink_input_idx) < 0) goto fail; pa_proplist_free(merged); if (e->lazy) time(&e->last_used_time); return 0; fail: pa_proplist_free(merged); return -1; }