char *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) { unsigned channel; pa_bool_t first = TRUE; char *e; pa_assert(s); pa_assert(l > 0); pa_assert(c); pa_init_i18n(); if (!pa_cvolume_valid(c)) { pa_snprintf(s, l, _("(invalid)")); return s; } *(e = s) = 0; for (channel = 0; channel < c->channels && l > 1; channel++) { double f = pa_sw_volume_to_dB(c->values[channel]); l -= pa_snprintf(e, l, "%s%u: %0.2f dB", first ? "" : " ", channel, isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); e = strchr(e, 0); first = FALSE; } return s; }
char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { unsigned channel; pa_bool_t first = TRUE; char *e; pa_assert(s); pa_assert(l > 0); pa_assert(c); pa_init_i18n(); if (!pa_cvolume_valid(c)) { pa_snprintf(s, l, _("(invalid)")); return s; } *(e = s) = 0; for (channel = 0; channel < c->channels && l > 1; channel++) { l -= pa_snprintf(e, l, "%s%u: %3u%%", first ? "" : " ", channel, (c->values[channel]*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM); e = strchr(e, 0); first = FALSE; } return s; }
pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { unsigned i; pa_assert(dest); pa_assert(a); pa_assert(b); pa_return_val_if_fail(pa_cvolume_valid(a), NULL); pa_return_val_if_fail(pa_cvolume_valid(b), NULL); for (i = 0; i < a->channels && i < b->channels; i++) dest->values[i] = PA_MAX(a->values[i], b->values[i]); dest->channels = (uint8_t) i; return dest; }
int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) { pa_assert(v); pa_assert(cm); pa_return_val_if_fail(pa_cvolume_valid(v), 0); pa_return_val_if_fail(pa_channel_map_valid(cm), 0); return v->channels == cm->channels; }
int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) { pa_assert(v); pa_assert(ss); pa_return_val_if_fail(pa_cvolume_valid(v), 0); pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); return v->channels == ss->channels; }
int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { int i; pa_assert(a); pa_assert(b); pa_return_val_if_fail(pa_cvolume_valid(a), 0); if (PA_UNLIKELY(a == b)) return 1; pa_return_val_if_fail(pa_cvolume_valid(b), 0); if (a->channels != b->channels) return 0; for (i = 0; i < a->channels; i++) if (a->values[i] != b->values[i]) return 0; return 1; }
pa_volume_t pa_cvolume_min(const pa_cvolume *a) { pa_volume_t m = PA_VOLUME_MAX; unsigned c; pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); for (c = 0; c < a->channels; c++) if (a->values[c] < m) m = a->values[c]; return m; }
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; }
pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { uint64_t sum = 0; unsigned c; pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); for (c = 0; c < a->channels; c++) sum += a->values[c]; sum /= a->channels; return (pa_volume_t) sum; }
static struct entry* read_entry(struct userdata *u, const char *name) { pa_datum key, data; struct entry *e; pa_assert(u); pa_assert(name); key.data = (char*) name; key.size = strlen(name); pa_zero(data); if (!pa_database_get(u->database, &key, &data)) goto fail; if (data.size != sizeof(struct entry)) { pa_log_debug("Database contains entry for device %s of wrong size %lu != %lu. Probably due to upgrade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry)); goto fail; } e = (struct entry*) data.data; if (e->version != ENTRY_VERSION) { pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name); goto fail; } if (!memchr(e->port, 0, sizeof(e->port))) { pa_log_warn("Database contains entry for device %s with missing NUL byte in port name", name); goto fail; } if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) { pa_log_warn("Invalid channel map stored in database for device %s", name); goto fail; } if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) { pa_log_warn("Volume and channel map don't match in database entry for device %s", name); goto fail; } return e; fail: pa_datum_free(&data); return NULL; }
static void stream_moved_cb(pa_stream *s, void *userdata) { audio_output_t *aout = userdata; aout_sys_t *sys = aout->sys; const char *name = pa_stream_get_device_name(s); struct sink *sink = sink_find(sys, pa_stream_get_device_index(s)); msg_Dbg(aout, "connected to sink %s", name); aout_DeviceReport(aout, name); sys->base_volume = likely(sink != NULL) ? sink->base_volume : PA_VOLUME_INVALID; msg_Dbg(aout, "base volume: %"PRIu32, sys->base_volume); if (pa_cvolume_valid(&sys->cvolume)) VolumeReport(aout); }
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); }
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; }
char *pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB) { char *current = s; bool first = true; pa_assert(s); pa_assert(l > 0); pa_assert(c); pa_init_i18n(); if (!pa_cvolume_valid(c)) { pa_snprintf(s, l, _("(invalid)")); return s; } pa_assert(!map || (map->channels == c->channels)); pa_assert(!map || pa_channel_map_valid(map)); current[0] = 0; for (unsigned channel = 0; channel < c->channels && l > 1; channel++) { char channel_position[32]; size_t bytes_printed; char buf[PA_VOLUME_SNPRINT_VERBOSE_MAX]; if (map) pa_snprintf(channel_position, sizeof(channel_position), "%s", pa_channel_position_to_string(map->map[channel])); else pa_snprintf(channel_position, sizeof(channel_position), "%u", channel); bytes_printed = pa_snprintf(current, l, "%s%s: %s", first ? "" : ", ", channel_position, pa_volume_snprint_verbose(buf, sizeof(buf), c->values[channel], print_dB)); l -= bytes_printed; current += bytes_printed; first = false; } return s; }
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 && volume != PA_VOLUME_INVALID) { 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 (volume != PA_VOLUME_INVALID) 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; }
/* Called from main context */ pa_source* pa_source_new( pa_core *core, pa_source_new_data *data, pa_source_flags_t flags) { pa_source *s; const char *name; char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; char *pt; pa_assert(core); pa_assert(data); pa_assert(data->name); pa_assert_ctl_context(); s = pa_msgobject_new(pa_source); if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) { pa_log_debug("Failed to register name %s.", data->name); pa_xfree(s); return NULL; } pa_source_new_data_set_name(data, name); if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) { pa_xfree(s); pa_namereg_unregister(core, name); return NULL; } /* FIXME, need to free s here on failure */ pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]); pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec)); if (!data->channel_map_is_set) pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT)); pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); if (!data->volume_is_set) pa_cvolume_reset(&data->volume, data->sample_spec.channels); pa_return_null_if_fail(pa_cvolume_valid(&data->volume)); pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec)); if (!data->muted_is_set) data->muted = FALSE; if (data->card) pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist); pa_device_init_description(data->proplist); pa_device_init_icon(data->proplist, FALSE); pa_device_init_intended_roles(data->proplist); if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) { pa_xfree(s); pa_namereg_unregister(core, name); return NULL; } s->parent.parent.free = source_free; s->parent.process_msg = pa_source_process_msg; s->core = core; s->state = PA_SOURCE_INIT; s->flags = flags; s->priority = 0; s->suspend_cause = 0; s->name = pa_xstrdup(name); s->proplist = pa_proplist_copy(data->proplist); s->driver = pa_xstrdup(pa_path_get_filename(data->driver)); s->module = data->module; s->card = data->card; s->priority = pa_device_init_priority(s->proplist); s->sample_spec = data->sample_spec; s->channel_map = data->channel_map; s->outputs = pa_idxset_new(NULL, NULL); s->n_corked = 0; s->monitor_of = NULL; s->output_from_master = NULL; s->volume = data->volume; pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); s->base_volume = PA_VOLUME_NORM; s->n_volume_steps = PA_VOLUME_NORM+1; s->muted = data->muted; s->refresh_volume = s->refresh_muted = FALSE; reset_callbacks(s); s->userdata = NULL; s->asyncmsgq = NULL; /* As a minor optimization we just steal the list instead of * copying it here */ s->ports = data->ports; data->ports = NULL; s->active_port = NULL; s->save_port = FALSE; if (data->active_port && s->ports) if ((s->active_port = pa_hashmap_get(s->ports, data->active_port))) s->save_port = data->save_port; if (!s->active_port && s->ports) { void *state; pa_device_port *p; PA_HASHMAP_FOREACH(p, s->ports, state) if (!s->active_port || p->priority > s->active_port->priority) s->active_port = p; }