static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) { char *name; struct entry *e; pa_assert(c); pa_assert(new_data); pa_assert(u); pa_assert(u->restore_volume || u->restore_muted); name = pa_sprintf_malloc("source:%s", new_data->name); if ((e = read_entry(u, name))) { if (u->restore_volume && e->volume_valid) { if (!new_data->volume_is_set) { pa_cvolume v; pa_log_info("Restoring volume for source %s.", new_data->name); v = e->volume; pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map); pa_source_new_data_set_volume(new_data, &v); new_data->save_volume = TRUE; } else pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name); } if (u->restore_muted && e->muted_valid) { if (!new_data->muted_is_set) { pa_log_info("Restoring mute state for source %s.", new_data->name); pa_source_new_data_set_muted(new_data, e->muted); new_data->save_muted = TRUE; } else pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name); } pa_xfree(e); } pa_xfree(name); return PA_HOOK_OK; }
static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) { pa_cvolume t; if (a->port_valid != b->port_valid || (a->port_valid && strncmp(a->port, b->port, sizeof(a->port)))) return FALSE; if (a->muted_valid != b->muted_valid || (a->muted_valid && (a->muted != b->muted))) return FALSE; t = b->volume; if (a->volume_valid != b->volume_valid || (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume))) return FALSE; return TRUE; }
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; }