+++ /dev/null
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulse/def.h>
-#include <pulsecore/card.h>
-
-#include "card-ext.h"
-#include "classify.h"
-#include "context.h"
-#include "discover.h"
-
-/* this included for the sake of pa_policy_send_device_state()
- which is temporarily hosted by sink-ext.c*/
-#include "sink-ext.h"
-
-
-/* hooks */
-static pa_hook_result_t card_put(void *, void *, void *);
-static pa_hook_result_t card_unlink(void *, void *, void *);
-static pa_hook_result_t card_profile_changed(void *, void *, void *);
-
-static void handle_new_card(struct userdata *, struct pa_card *);
-static void handle_removed_card(struct userdata *, struct pa_card *);
-
-
-struct pa_card_evsubscr *pa_card_ext_subscription(struct userdata *u)
-{
- pa_core *core;
- pa_hook *hooks;
- struct pa_card_evsubscr *subscr;
- pa_hook_slot *put;
- pa_hook_slot *unlink;
- pa_hook_slot *profchg;
-
- pa_assert(u);
- pa_assert_se((core = u->core));
-
- hooks = core->hooks;
-
- put = pa_hook_connect(hooks + PA_CORE_HOOK_CARD_PUT,
- PA_HOOK_LATE, card_put, (void *)u);
- unlink = pa_hook_connect(hooks + PA_CORE_HOOK_CARD_UNLINK,
- PA_HOOK_LATE, card_unlink, (void *)u);
- profchg = pa_hook_connect(hooks + PA_CORE_HOOK_CARD_PROFILE_CHANGED,
- PA_HOOK_LATE, card_profile_changed, (void *)u);
-
-
- subscr = pa_xnew0(struct pa_card_evsubscr, 1);
-
- subscr->put = put;
- subscr->unlink = unlink;
- subscr->profchg = profchg;
-
- return subscr;
-
-
-}
-
-void pa_card_ext_subscription_free(struct pa_card_evsubscr *subscr)
-{
- if (subscr != NULL) {
- pa_hook_slot_free(subscr->put);
- pa_hook_slot_free(subscr->unlink);
- pa_hook_slot_free(subscr->profchg);
-
- pa_xfree(subscr);
- }
-}
-
-void pa_card_ext_discover(struct userdata *u)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_card *card;
-
- pa_assert(u);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->cards));
-
- pa_policy_new_stamp();
-
- while ((card = pa_idxset_iterate(idxset, &state, NULL)) != NULL)
- handle_new_card(u, card);
-}
-
-char *pa_card_ext_get_name(struct pa_card *card)
-{
- return card->name ? card->name : (char *)"<unknown>";
-}
-
-char **pa_card_ext_get_profiles(struct pa_card *card)
-{
-#define MAX_PROF 16
-
- pa_card_profile *p;
- char **plist = NULL;
- int size = sizeof(char *) * MAX_PROF;
- void *st;
- int l;
-
- if (card->profiles && (plist = pa_xmalloc(size)) != NULL) {
- memset(plist, 0, size);
-
- for (l = 0, st = NULL;
- (p = pa_hashmap_iterate(card->profiles,&st,NULL)) && l < MAX_PROF;
- l++)
- {
- plist[l] = p->name;
- }
-
- }
-
- return plist;
-
-#undef MAX_PROF
-}
-
-int pa_card_ext_set_profile(struct userdata *u, char *type)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_card *card;
- struct pa_classify_card_data *data;
- char *pn;
- char *cn;
- pa_card_profile *ap;
- int sts;
-
- pa_assert(u);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->cards));
-
- sts = 0;
-
- while ((card = pa_idxset_iterate(idxset, &state, NULL)) != NULL) {
- if (pa_classify_is_card_typeof(u, card, type, &data)) {
-
- ap = card->active_profile;
- pn = data->profile;
- cn = pa_card_ext_get_name(card);
-
- if (pn && (!ap || strcmp(pn, ap->name))) {
- if (pa_card_set_profile(card, pn, FALSE) < 0) {
- sts = -1;
- pa_log("failed to set card '%s' profile to '%s'", cn, pn);
- }
- else {
- pa_log_debug("%s: changed card '%s' profile to '%s'",
- __FILE__, cn, pn);
- }
- }
-
- break;
- }
- }
-
- return sts;
-}
-
-static pa_hook_result_t card_put(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_card *card = (struct pa_card *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- pa_policy_new_stamp();
- handle_new_card(u, card);
-
- return PA_HOOK_OK;
-}
-
-
-static pa_hook_result_t card_unlink(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_card *card = (struct pa_card *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_removed_card(u, card);
-
- return PA_HOOK_OK;
-}
-
-
-static pa_hook_result_t card_profile_changed(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_card *card = (struct pa_card *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- pa_policy_new_stamp();
- pa_discover_profile_changed(u, card);
-
- return PA_HOOK_OK;
-}
-
-
-static void handle_new_card(struct userdata *u, struct pa_card *card)
-{
- char *name;
- uint32_t idx;
- char buf[1024];
- int len;
- int ret;
-
- if (card && u) {
- name = pa_card_ext_get_name(card);
- idx = card->index;
- len = pa_classify_card(u, card, 0,0, buf, sizeof(buf));
-
- pa_policy_context_register(u, pa_policy_object_card, name, card);
-
- pa_discover_add_card(u, card);
-
- if (len <= 0)
- pa_log_debug("new card '%s' (idx=%d)", name, idx);
- else {
- ret = pa_proplist_sets(card->proplist,
- PA_PROP_POLICY_CARDTYPELIST, buf);
-
- if (ret < 0) {
- pa_log("failed to set property '%s' on card '%s'",
- PA_PROP_POLICY_DEVTYPELIST, name);
- }
- else {
- pa_log_debug("new card '%s' (idx=%d) (type %s)",
- name, idx, buf);
-
- len = pa_classify_card(u, card, PA_POLICY_DISABLE_NOTIFY, 0,
- buf, sizeof(buf));
- if (len > 0) {
- pa_policy_send_device_state(u, PA_POLICY_CONNECTED, buf);
- }
- }
- }
- }
-}
-
-static void handle_removed_card(struct userdata *u, struct pa_card *card)
-{
- char *name;
- uint32_t idx;
- char buf[1024];
- int len;
-
- if (card && u) {
- name = pa_card_ext_get_name(card);
- idx = card->index;
- len = pa_classify_card(u, card, 0,0, buf, sizeof(buf));
-
- pa_policy_context_unregister(u, pa_policy_object_card, name, card,idx);
-
- pa_discover_remove_card(u, card);
-
- if (len <= 0)
- pa_log_debug("remove card '%s' (idx=%d)", name, idx);
- else {
- pa_log_debug("remove card '%s' (idx=%d, type=%s)", name,idx, buf);
-
- len = pa_classify_card(u, card, PA_POLICY_DISABLE_NOTIFY, 0,
- buf, sizeof(buf));
- if (len > 0) {
- pa_policy_send_device_state(u, PA_POLICY_DISCONNECTED, buf);
- }
- }
- }
-}
-
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef foocardextfoo
-#define foocardextfoo
-
-#include "userdata.h"
-
-struct pa_card_evsubscr {
- pa_hook_slot *put;
- pa_hook_slot *unlink;
- pa_hook_slot *profchg;
-};
-
-struct pa_card_evsubscr *pa_card_ext_subscription(struct userdata *);
-void pa_card_ext_subscription_free(struct pa_card_evsubscr *);
-void pa_card_ext_discover(struct userdata *);
-char *pa_card_ext_get_name(struct pa_card *);
-char **pa_card_ext_get_profiles(struct pa_card *);
-int pa_card_ext_set_profile(struct userdata *, char *);
-
-#endif
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <stdio.h>
-
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulsecore/client.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/log.h>
-#include <pulsecore/sink-input.h>
-#include <pulsecore/source-output.h>
-#include <pulsecore/strbuf.h>
-
-#include "classify.h"
-#include "policy-group.h"
-#include "client-ext.h"
-#include "sink-ext.h"
-#include "source-ext.h"
-#include "card-ext.h"
-#include "sink-input-ext.h"
-#include "source-output-ext.h"
-
-
-
-static char *find_group_for_client(struct userdata *, struct pa_client *,
- pa_proplist *, uint32_t *);
-#if 0
-static char *arg_dump(int, char **, char *, size_t);
-#endif
-
-static void pid_hash_free(struct pa_classify_pid_hash **);
-static void pid_hash_insert(struct pa_classify_pid_hash **, pid_t,
- const char *, enum pa_classify_method,
- const char *, const char *);
-static void pid_hash_remove(struct pa_classify_pid_hash **, pid_t,
- const char *, enum pa_classify_method,
- const char *);
-static char *pid_hash_get_group(struct pa_classify_pid_hash **, pid_t,
- pa_proplist *);
-static struct pa_classify_pid_hash
- *pid_hash_find(struct pa_classify_pid_hash **, pid_t,
- const char *, enum pa_classify_method, const char *,
- struct pa_classify_pid_hash **);
-
-static void streams_free(struct pa_classify_stream_def *);
-static void streams_add(struct pa_classify_stream_def **, char *,
- enum pa_classify_method, char *, char *,
- uid_t, char *, char *, uint32_t);
-static char *streams_get_group(struct pa_classify_stream_def **, pa_proplist *,
- char *, uid_t, char *, uint32_t *);
-static struct pa_classify_stream_def
- *streams_find(struct pa_classify_stream_def **, pa_proplist *,
- char *, uid_t, char *,
- struct pa_classify_stream_def **);
-
-static void devices_free(struct pa_classify_device *);
-static void devices_add(struct pa_classify_device **, char *,
- char *, enum pa_classify_method, char *, pa_hashmap *,
- uint32_t);
-static int devices_classify(struct pa_classify_device_def *, pa_proplist *,
- char *, uint32_t, uint32_t, char *, int);
-static int devices_is_typeof(struct pa_classify_device_def *, pa_proplist *,
- char *, const char *,
- struct pa_classify_device_data **);
-
-static void cards_free(struct pa_classify_card *);
-static void cards_add(struct pa_classify_card **, char *,
- enum pa_classify_method, char *, char *, uint32_t);
-static int cards_classify(struct pa_classify_card_def *, char *, char **,
- uint32_t,uint32_t, char *,int);
-static int card_is_typeof(struct pa_classify_card_def *, char *,
- char *, struct pa_classify_card_data **);
-
-static int port_device_is_typeof(struct pa_classify_device_def *, char *,
- const char *,
- struct pa_classify_device_data **);
-
-static const char *method_str(enum pa_classify_method);
-
-char *get_property(char *, pa_proplist *, char *);
-
-
-
-struct pa_classify *pa_classify_new(struct userdata *u)
-{
- struct pa_classify *cl;
-
- cl = pa_xnew0(struct pa_classify, 1);
-
- cl->sinks = pa_xnew0(struct pa_classify_device, 1);
- cl->sources = pa_xnew0(struct pa_classify_device, 1);
- cl->cards = pa_xnew0(struct pa_classify_card, 1);
-
- return cl;
-}
-
-void pa_classify_free(struct pa_classify *cl)
-{
- if (cl) {
- pid_hash_free(cl->streams.pid_hash);
- streams_free(cl->streams.defs);
- devices_free(cl->sinks);
- devices_free(cl->sources);
- cards_free(cl->cards);
-
- pa_xfree(cl);
- }
-}
-
-void pa_classify_add_sink(struct userdata *u, char *type, char *prop,
- enum pa_classify_method method, char *arg,
- pa_hashmap *ports, uint32_t flags)
-{
- struct pa_classify *classify;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->sinks);
- pa_assert(type);
- pa_assert(prop);
- pa_assert(arg);
-
- devices_add(&classify->sinks, type, prop, method, arg, ports, flags);
-}
-
-void pa_classify_add_source(struct userdata *u, char *type, char *prop,
- enum pa_classify_method method, char *arg,
- pa_hashmap *ports, uint32_t flags)
-{
- struct pa_classify *classify;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->sources);
- pa_assert(type);
- pa_assert(prop);
- pa_assert(arg);
-
- devices_add(&classify->sources, type, prop, method, arg, ports, flags);
-}
-
-void pa_classify_add_card(struct userdata *u, char *type,
- enum pa_classify_method method, char *arg,
- char *profile, uint32_t flags)
-{
- struct pa_classify *classify;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->cards);
- pa_assert(type);
- pa_assert(arg);
-
- cards_add(&classify->cards, type, method, arg, profile, flags);
-}
-
-
-void pa_classify_add_stream(struct userdata *u, char *prop,
- enum pa_classify_method method, char *arg,
- char *clnam, uid_t uid, char *exe, char *grnam,
- uint32_t flags, char *port)
-{
- struct pa_classify *classify;
- struct pa_policy_group *group;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
-
- if (((prop && method && arg) || uid != (uid_t)-1 || exe) && grnam) {
- if (port) {
- if ((group = pa_policy_group_find(u, grnam)) == NULL) {
- flags &= ~PA_POLICY_LOCAL_ROUTE;
- pa_log("can't find group '%s' for stream", grnam);
- }
- else {
- group->portname = pa_xstrdup(port);
- pa_log_debug("set portname '%s' for group '%s'", port, grnam);
- }
- }
-
- streams_add(&classify->streams.defs, prop,method,arg,
- clnam, uid, exe, grnam, flags);
- }
-}
-
-void pa_classify_register_pid(struct userdata *u, pid_t pid, char *prop,
- enum pa_classify_method method, char *arg,
- char *group)
-{
- struct pa_classify *classify;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
-
- if (pid && group) {
- pid_hash_insert(classify->streams.pid_hash, pid,
- prop, method, arg, group);
- }
-}
-
-void pa_classify_unregister_pid(struct userdata *u, pid_t pid, char *prop,
- enum pa_classify_method method, char *arg)
-{
- struct pa_classify *classify;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
-
- if (pid) {
- pid_hash_remove(classify->streams.pid_hash, pid, prop, method, arg);
- }
-}
-
-char *pa_classify_sink_input(struct userdata *u, struct pa_sink_input *sinp,
- uint32_t *flags)
-{
- struct pa_client *client;
- char *group;
-
- pa_assert(u);
- pa_assert(sinp);
-
- client = sinp->client;
- group = find_group_for_client(u, client, sinp->proplist, flags);
-
- return group;
-}
-
-char *pa_classify_sink_input_by_data(struct userdata *u,
- struct pa_sink_input_new_data *data,
- uint32_t *flags)
-{
- struct pa_client *client;
- char *group;
-
- pa_assert(u);
- pa_assert(data);
-
- client = data->client;
- group = find_group_for_client(u, client, data->proplist, flags);
-
- return group;
-}
-
-char *pa_classify_source_output(struct userdata *u,
- struct pa_source_output *sout)
-{
- struct pa_client *client;
- char *group;
-
- pa_assert(u);
- pa_assert(sout);
-
- client = sout->client;
- group = find_group_for_client(u, client, sout->proplist, NULL);
-
- return group;
-}
-
-char *
-pa_classify_source_output_by_data(struct userdata *u,
- struct pa_source_output_new_data *data)
-{
- struct pa_client *client;
- char *group;
-
- pa_assert(u);
- pa_assert(data);
-
- client = data->client;
- group = find_group_for_client(u, client, data->proplist, NULL);
-
- return group;
-}
-
-int pa_classify_sink(struct userdata *u, struct pa_sink *sink,
- uint32_t flag_mask, uint32_t flag_value,
- char *buf, int len)
-{
- struct pa_classify *classify;
- struct pa_classify_device_def *defs;
- char *name;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->sinks);
- pa_assert_se((defs = classify->sinks->defs));
-
- name = pa_sink_ext_get_name(sink);
-
- return devices_classify(defs, sink->proplist, name,
- flag_mask, flag_value, buf, len);
-}
-
-int pa_classify_source(struct userdata *u, struct pa_source *source,
- uint32_t flag_mask, uint32_t flag_value,
- char *buf, int len)
-{
- struct pa_classify *classify;
- struct pa_classify_device_def *defs;
- char *name;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->sources);
- pa_assert_se((defs = classify->sources->defs));
-
- name = pa_source_ext_get_name(source);
-
- return devices_classify(defs, source->proplist, name,
- flag_mask, flag_value, buf, len);
-}
-
-int pa_classify_card(struct userdata *u, struct pa_card *card,
- uint32_t flag_mask, uint32_t flag_value,
- char *buf, int size)
-{
- struct pa_classify *classify;
- struct pa_classify_card_def *defs;
- char *name;
- char **profs;
- int len;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->cards);
- pa_assert_se((defs = classify->cards->defs));
-
- name = pa_card_ext_get_name(card);
- profs = pa_card_ext_get_profiles(card);
-
- len = cards_classify(defs, name,profs, flag_mask,flag_value, buf,size);
-
- pa_xfree(profs);
-
- return len;
-}
-
-int pa_classify_is_sink_typeof(struct userdata *u, struct pa_sink *sink,
- const char *type,
- struct pa_classify_device_data **d)
-{
- struct pa_classify *classify;
- struct pa_classify_device_def *defs;
- char *name;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->sinks);
- pa_assert_se((defs = classify->sinks->defs));
-
- if (!sink || !type)
- return FALSE;
-
- name = pa_sink_ext_get_name(sink);
-
- return devices_is_typeof(defs, sink->proplist, name, type, d);
-}
-
-
-int pa_classify_is_source_typeof(struct userdata *u, struct pa_source *source,
- const char *type,
- struct pa_classify_device_data **d)
-{
- struct pa_classify *classify;
- struct pa_classify_device_def *defs;
- char *name;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->sources);
- pa_assert_se((defs = classify->sources->defs));
-
- if (!source || !type)
- return FALSE;
-
- name = pa_source_ext_get_name(source);
-
- return devices_is_typeof(defs, source->proplist, name, type, d);
-}
-
-
-int pa_classify_is_card_typeof(struct userdata *u, struct pa_card *card,
- char *type, struct pa_classify_card_data **d)
-{
- struct pa_classify *classify;
- struct pa_classify_card_def *defs;
- char *name;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->cards);
- pa_assert_se((defs = classify->cards->defs));
-
- if (!card || !type)
- return FALSE;
-
- name = pa_card_ext_get_name(card);
-
- return card_is_typeof(defs, name, type, d);
-}
-
-
-int pa_classify_is_port_sink_typeof(struct userdata *u, struct pa_sink *sink,
- const char *type,
- struct pa_classify_device_data **d)
-{
- struct pa_classify *classify;
- struct pa_classify_device_def *defs;
- char *name;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->sinks);
- pa_assert_se((defs = classify->sinks->defs));
-
- if (!sink || !type)
- return FALSE;
-
- name = pa_sink_ext_get_name(sink);
-
- return port_device_is_typeof(defs, name, type, d);
-}
-
-
-int pa_classify_is_port_source_typeof(struct userdata *u,
- struct pa_source *source,
- const char *type,
- struct pa_classify_device_data **d)
-{
- struct pa_classify *classify;
- struct pa_classify_device_def *defs;
- char *name;
-
- pa_assert(u);
- pa_assert_se((classify = u->classify));
- pa_assert(classify->sources);
- pa_assert_se((defs = classify->sources->defs));
-
- if (!source || !type)
- return FALSE;
-
- name = pa_source_ext_get_name(source);
-
- return port_device_is_typeof(defs, name, type, d);
-}
-
-
-static char *find_group_for_client(struct userdata *u,
- struct pa_client *client,
- pa_proplist *proplist,
- uint32_t *flags_ret)
-{
- struct pa_classify *classify;
- struct pa_classify_pid_hash **hash;
- struct pa_classify_stream_def **defs;
- pid_t pid = 0; /* client processs PID */
- char *clnam = (char *)""; /* client's name in PA */
- uid_t uid = (uid_t)-1; /* client process user ID */
- char *exe = (char *)""; /* client's binary path */
- char *arg0;
- char *group = NULL;
- uint32_t flags = 0;
-
- assert(u);
- pa_assert_se((classify = u->classify));
-
- hash = classify->streams.pid_hash;
- defs = &classify->streams.defs;
-
- if (client == NULL)
- group = streams_get_group(defs, proplist, clnam, uid, exe, &flags);
- else {
- pid = pa_client_ext_pid(client);
-
- if ((group = pid_hash_get_group(hash, pid, proplist)) == NULL) {
- clnam = pa_client_ext_name(client);
- uid = pa_client_ext_uid(client);
- exe = pa_client_ext_exe(client);
- arg0 = pa_client_ext_arg0(client);
-
- group = streams_get_group(defs, proplist, clnam, uid, exe, &flags);
- }
- }
-
- if (group == NULL)
- group = (char *)PA_POLICY_DEFAULT_GROUP_NAME;
-
- pa_log_debug("%s (%s|%d|%d|%s) => %s,0x%x", __FUNCTION__,
- clnam?clnam:"<null>", pid, uid, exe?exe:"<null>",
- group?group:"<null>", flags);
-
- if (flags_ret != NULL)
- *flags_ret = flags;
-
- return group;
-}
-
-#if 0
-static char *arg_dump(int argc, char **argv, char *buf, size_t len)
-{
- char *p = buf;
- int i, l;
-
- if (argc <= 0 || argv == NULL)
- snprintf(buf, len, "0 <null>");
- else {
- l = snprintf(p, len, "%d", argc);
-
- p += l;
- len -= l;
-
- for (i = 0; i < argc && len > 0; i++) {
- l = snprintf(p, len, " [%d]=%s", i, argv[i]);
-
- p += l;
- len -= l;
- }
- }
-
- return buf;
-}
-#endif
-
-static void pid_hash_free(struct pa_classify_pid_hash **hash)
-{
- struct pa_classify_pid_hash *st;
- int i;
-
- assert(hash);
-
- for (i = 0; i < PA_POLICY_PID_HASH_MAX; i++) {
- while ((st = hash[i]) != NULL) {
- hash[i] = st->next;
-
- pa_xfree(st->prop);
- pa_xfree(st->group);
- pa_xfree(st->arg.def);
-
- if (st->method.type == pa_method_matches)
- regfree(&st->arg.value.rexp);
-
- pa_xfree(st);
- }
- }
-}
-
-static void pid_hash_insert(struct pa_classify_pid_hash **hash, pid_t pid,
- const char *prop, enum pa_classify_method method,
- const char *arg, const char *group)
-{
- struct pa_classify_pid_hash *st;
- struct pa_classify_pid_hash *prev;
-
- pa_assert(hash);
- pa_assert(group);
-
- if ((st = pid_hash_find(hash, pid, prop,method,arg, &prev))) {
- pa_xfree(st->group);
- st->group = pa_xstrdup(group);
-
- pa_log_debug("pid hash group changed (%u|%s|%s|%s|%s)", st->pid,
- st->prop ? st->prop : "", method_str(st->method.type),
- st->arg.def ? st->arg.def : "", st->group);
- }
- else {
- st = pa_xnew0(struct pa_classify_pid_hash, 1);
-
- st->next = prev->next;
- st->pid = pid;
- st->prop = prop ? pa_xstrdup(prop) : NULL;
- st->group = pa_xstrdup(group);
-
- if (!prop)
- st->arg.def = pa_xstrdup("");
- else {
- st->method.type = method;
-
- switch (method) {
-
- case pa_method_equals:
- st->method.func = pa_classify_method_equals;
- st->arg.value.string = st->arg.def = pa_xstrdup(arg ? arg:"");
- break;
-
- case pa_method_startswith:
- st->method.func = pa_classify_method_startswith;
- st->arg.value.string = st->arg.def = pa_xstrdup(arg ? arg:"");
- break;
-
- case pa_method_matches:
- st->method.func = pa_classify_method_matches;
- st->arg.def = pa_xstrdup(arg ? arg:"");
- if (!arg || regcomp(&st->arg.value.rexp, arg, 0) != 0) {
- st->method.type = pa_method_true;
- st->method.func = pa_classify_method_true;
- }
- break;
-
- default:
- case pa_method_true:
- st->method.func = pa_classify_method_true;
- break;
- }
- }
-
- prev->next = st;
-
- pa_log_debug("pid hash added (%u|%s|%s|%s|%s)", st->pid,
- st->prop ? st->prop : "", method_str(st->method.type),
- st->arg.def ? st->arg.def : "", st->group);
- }
-}
-
-static void pid_hash_remove(struct pa_classify_pid_hash **hash,
- pid_t pid, const char *prop,
- enum pa_classify_method method, const char *arg)
-{
- struct pa_classify_pid_hash *st;
- struct pa_classify_pid_hash *prev;
-
- pa_assert(hash);
-
- if ((st = pid_hash_find(hash, pid, prop,method,arg, &prev)) != NULL) {
- prev->next = st->next;
-
- pa_xfree(st->prop);
- pa_xfree(st->group);
- pa_xfree(st->arg.def);
-
- if (st->method.type == pa_method_matches)
- regfree(&st->arg.value.rexp);
-
- pa_xfree(st);
- }
-}
-
-static char *pid_hash_get_group(struct pa_classify_pid_hash **hash,
- pid_t pid, pa_proplist *proplist)
-{
- struct pa_classify_pid_hash *st;
- int idx;
- char *propval;
- char *group = NULL;
-
- pa_assert(hash);
-
- if (pid) {
- idx = pid & PA_POLICY_PID_HASH_MASK;
-
- for (st = hash[idx]; st != NULL; st = st->next) {
- if (pid == st->pid) {
- if (!st->prop) {
- group = st->group;
- break;
- }
-
- if ((propval = (char *)pa_proplist_gets(proplist, st->prop)) &&
- st->method.func(propval, &st->arg.value))
- {
- group = st->group;
- break;
- }
- }
- }
- }
-
- return group;
-}
-
-static struct
-pa_classify_pid_hash *pid_hash_find(struct pa_classify_pid_hash **hash,
- pid_t pid, const char *prop,
- enum pa_classify_method method,
- const char *arg,
- struct pa_classify_pid_hash **prev_ret)
-{
- struct pa_classify_pid_hash *st;
- struct pa_classify_pid_hash *prev;
- int idx;
-
- idx = pid & PA_POLICY_PID_HASH_MASK;
-
- for (prev = (struct pa_classify_pid_hash *)&hash[idx];
- (st = prev->next) != NULL;
- prev = prev->next)
- {
- if (pid && pid == st->pid) {
- if (!prop && !st->prop)
- break;
-
- if (st->prop && method == st->method.type) {
- if (method == pa_method_true)
- break;
-
- if (arg && st->arg.def && !strcmp(arg, st->arg.def))
- break;
- }
- }
- }
-
- if (prev_ret)
- *prev_ret = prev;
-
-#if 0
- pa_log_debug("%s(%d,'%s') => %p", __FUNCTION__,
- pid, stnam?stnam:"<null>", st);
-#endif
-
- return st;
-}
-
-static void streams_free(struct pa_classify_stream_def *defs)
-{
- struct pa_classify_stream_def *stream;
- struct pa_classify_stream_def *next;
-
- for (stream = defs; stream; stream = next) {
- next = stream->next;
-
- if (stream->method == pa_classify_method_matches)
- regfree(&stream->arg.rexp);
- else
- pa_xfree((void *)stream->arg.string);
-
- pa_xfree(stream->prop);
- pa_xfree(stream->exe);
- pa_xfree(stream->clnam);
- pa_xfree(stream->group);
-
- pa_xfree(stream);
- }
-}
-
-static void streams_add(struct pa_classify_stream_def **defs, char *prop,
- enum pa_classify_method method,char *arg, char *clnam,
- uid_t uid, char *exe, char *group, uint32_t flags)
-{
- struct pa_classify_stream_def *d;
- struct pa_classify_stream_def *prev;
- pa_proplist *proplist = NULL;
- char method_def[256];
-
- pa_assert(defs);
- pa_assert(group);
-
- proplist = pa_proplist_new();
-
- if (prop && arg && (method == pa_method_equals)) {
- pa_proplist_sets(proplist, prop, arg);
- }
-
- if ((d = streams_find(defs, proplist, clnam, uid, exe, &prev)) != NULL) {
- pa_log_info("%s: redefinition of stream", __FILE__);
- pa_xfree(d->group);
- }
- else {
- d = pa_xnew0(struct pa_classify_stream_def, 1);
-
- snprintf(method_def, sizeof(method_def), "<no-property-check>");
-
- if (prop && arg && method > pa_method_min && method < pa_method_max) {
- d->prop = pa_xstrdup(prop);
-
- switch (method) {
-
- case pa_method_equals:
- snprintf(method_def, sizeof(method_def),
- "%s equals:%s", prop, arg);
- d->method = pa_classify_method_equals;
- d->arg.string = pa_xstrdup(arg);
- break;
-
- case pa_method_startswith:
- snprintf(method_def, sizeof(method_def),
- "%s startswith:%s",prop, arg);
- d->method = pa_classify_method_startswith;
- d->arg.string = pa_xstrdup(arg);
- break;
-
- case pa_method_matches:
- snprintf(method_def, sizeof(method_def),
- "%s matches:%s",prop, arg);
- d->method = pa_classify_method_matches;
- if (regcomp(&d->arg.rexp, arg, 0) != 0) {
- pa_log("%s: invalid regexp definition '%s'",
- __FUNCTION__, arg);
- pa_assert_se(0);
- }
- break;
-
-
- case pa_method_true:
- snprintf(method_def, sizeof(method_def), "%s true", prop);
- d->method = pa_classify_method_true;
- memset(&d->arg, 0, sizeof(d->arg));
- break;
-
- default:
- /* never supposed to get here. just keep the compiler happy */
- pa_assert_se(0);
- break;
- }
- }
-
- d->uid = uid;
- d->exe = exe ? pa_xstrdup(exe) : NULL;
- d->clnam = clnam ? pa_xstrdup(clnam) : NULL;
-
- prev->next = d;
-
- pa_log_debug("stream added (%d|%s|%s|%s)", uid, exe?exe:"<null>",
- clnam?clnam:"<null>", method_def);
- }
-
- d->group = pa_xstrdup(group);
- d->flags = flags;
-
- pa_proplist_free(proplist);
-}
-
-static char *streams_get_group(struct pa_classify_stream_def **defs,
- pa_proplist *proplist,
- char *clnam, uid_t uid, char *exe,
- uint32_t *flags_ret)
-{
- struct pa_classify_stream_def *d;
- char *group;
- uint32_t flags;
-
- pa_assert(defs);
-
- if ((d = streams_find(defs, proplist, clnam, uid, exe, NULL)) == NULL) {
- group = NULL;
- flags = 0;
- }
- else {
- group = d->group;
- flags = d->flags;
- }
-
- if (flags_ret != NULL)
- *flags_ret = flags;
-
- return group;
-}
-
-static struct pa_classify_stream_def *
-streams_find(struct pa_classify_stream_def **defs, pa_proplist *proplist,
- char *clnam, uid_t uid, char *exe,
- struct pa_classify_stream_def **prev_ret)
-{
-#define PROPERTY_MATCH (!d->prop || !d->method || \
- (d->method && d->method(prv, &d->arg)))
-#define STRING_MATCH_OF(m) (!d->m || (m && d->m && !strcmp(m, d->m)))
-#define ID_MATCH_OF(m) (d->m == -1 || m == d->m)
-
- struct pa_classify_stream_def *prev;
- struct pa_classify_stream_def *d;
- char *prv;
-
- for (prev = (struct pa_classify_stream_def *)defs;
- (d = prev->next) != NULL;
- prev = prev->next)
- {
- if (!proplist || !d->prop ||
- !(prv = (char *)pa_proplist_gets(proplist, d->prop)) || !prv[0])
- {
- prv = (char *)"<unknown>";
- }
-
-#if 0
- if (d->method == pa_classify_method_matches) {
- pa_log_debug("%s: prv='%s' prop='%s' arg=<regexp>",
- __FUNCTION__, prv, d->prop?d->prop:"<null>");
- }
- else {
- pa_log_debug("%s: prv='%s' prop='%s' arg='%s'",
- __FUNCTION__, prv, d->prop?d->prop:"<null>",
- d->arg.string?d->arg.string:"<null>");
- }
-#endif
-
- if (PROPERTY_MATCH &&
- STRING_MATCH_OF(clnam) &&
- ID_MATCH_OF(uid) &&
- STRING_MATCH_OF(exe) )
- break;
-
- }
-
- if (prev_ret)
- *prev_ret = prev;
-
-#if 0
- {
- char *s = pa_proplist_to_string_sep(proplist, " ");
- pa_log_debug("%s(<%s>,'%s',%d,'%s') => %p", __FUNCTION__,
- s, clnam?clnam:"<null>", uid, exe?exe:"<null>", d);
- pa_xfree(s);
- }
-#endif
-
- return d;
-
-#undef STRING_MATCH_OF
-#undef ID_MATCH_OF
-}
-
-void pa_classify_port_entry_free(struct pa_classify_port_entry *port) {
- pa_assert(port);
-
- pa_xfree(port->device_name);
- pa_xfree(port->port_name);
- pa_xfree(port);
-}
-
-static void devices_free(struct pa_classify_device *devices)
-{
- struct pa_classify_device_def *d;
-
- if (devices) {
- for (d = devices->defs; d->type; d++) {
- pa_xfree((void *)d->type);
-
- if (d->data.ports) {
- struct pa_classify_port_entry *port;
-
- while ((port = pa_hashmap_steal_first(d->data.ports)))
- pa_classify_port_entry_free(port);
-
- pa_hashmap_free(d->data.ports, NULL, NULL);
- }
-
- if (d->method == pa_classify_method_matches)
- regfree(&d->arg.rexp);
- else
- pa_xfree((void *)d->arg.string);
- }
-
- pa_xfree(devices);
- }
-}
-
-static void devices_add(struct pa_classify_device **p_devices, char *type,
- char *prop, enum pa_classify_method method, char *arg,
- pa_hashmap *ports, uint32_t flags)
-{
- struct pa_classify_device *devs;
- struct pa_classify_device_def *d;
- size_t newsize;
- char *method_name;
- char *ports_string = NULL; /* Just for log output. */
- pa_strbuf *buf; /* For building ports_string. */
-
- pa_assert(p_devices);
- pa_assert_se((devs = *p_devices));
-
- newsize = sizeof(*devs) + sizeof(devs->defs[0]) * (devs->ndef + 1);
-
- devs = *p_devices = pa_xrealloc(devs, newsize);
-
- d = devs->defs + devs->ndef;
-
- memset(d+1, 0, sizeof(devs->defs[0]));
-
- d->type = pa_xstrdup(type);
- d->prop = pa_xstrdup(prop);
-
- buf = pa_strbuf_new();
-
- if (ports && !pa_hashmap_isempty(ports)) {
- struct pa_classify_port_entry *port;
- void *state;
- pa_bool_t first = TRUE;
-
- /* Copy the ports hashmap to d->data.ports. */
-
-#if PULSEAUDIO_HAS_PORTS
- d->data.ports = pa_hashmap_new(pa_idxset_string_hash_func,
- pa_idxset_string_compare_func);
- PA_HASHMAP_FOREACH(port, ports, state) {
- struct pa_classify_port_entry *port_copy =
- pa_xnew(struct pa_classify_port_entry, 1);
-
- port_copy->device_name = pa_xstrdup(port->device_name);
- port_copy->port_name = pa_xstrdup(port->port_name);
-
- pa_hashmap_put(d->data.ports, port_copy->device_name, port_copy);
-
- if (!first) {
- pa_strbuf_putc(buf, ',');
- }
- first = FALSE;
-
- pa_strbuf_printf(buf, "%s:%s", port->device_name, port->port_name);
- }
-#else
- d->data.ports = NULL;
-#endif
- }
-
- d->data.flags = flags;
-
- switch (method) {
-
- case pa_method_equals:
- method_name = "equals";
- d->method = pa_classify_method_equals;
- d->arg.string = pa_xstrdup(arg);
- break;
-
- case pa_method_startswith:
- method_name = "startswidth";
- d->method = pa_classify_method_startswith;
- d->arg.string = pa_xstrdup(arg);
- break;
-
- case pa_method_matches:
- method_name = "matches";
- if (regcomp(&d->arg.rexp, arg, 0) == 0) {
- d->method = pa_classify_method_matches;
- break;
- }
- /* intentional fall trough */
-
- default:
- pa_log("%s: invalid device definition %s", __FUNCTION__, type);
- memset(d, 0, sizeof(*d));
- return;
- }
-
- devs->ndef++;
-
- ports_string = pa_strbuf_tostring_free(buf);
-
- pa_log_info("device '%s' added (%s|%s|%s|%s|0x%04x)",
- type, d->prop, method_name, arg, ports_string, d->data.flags);
-
- pa_xfree(ports_string);
-}
-
-static int devices_classify(struct pa_classify_device_def *defs,
- pa_proplist *proplist, char *name,
- uint32_t flag_mask, uint32_t flag_value,
- char *buf, int len)
-{
- struct pa_classify_device_def *d;
- char *propval;
- int i;
- char *p;
- char *e;
- const char *s;
-
- pa_assert(buf);
- pa_assert(len > 0);
-
- e = (p = buf) + len;
- p[0] = '\0';
- s = "";
-
- for (d = defs, i = 0; d->type; d++) {
- propval = get_property(d->prop, proplist, name);
-
- if (d->method(propval, &d->arg)) {
- if ((d->data.flags & flag_mask) == flag_value) {
- p += snprintf(p, (size_t)(e-p), "%s%s", s, d->type);
- s = " ";
-
- if (p > e) {
- pa_log("%s: %s() buffer overflow", __FILE__, __FUNCTION__);
- *buf = '\0';
- p = e;
- break;
- }
- }
- }
- }
-
- return (e - p);
-}
-
-static int devices_is_typeof(struct pa_classify_device_def *defs,
- pa_proplist *proplist, char *name,
- const char *type,
- struct pa_classify_device_data **data)
-{
- struct pa_classify_device_def *d;
- char *propval;
-
- for (d = defs; d->type; d++) {
- if (!strcmp(type, d->type)) {
- propval = get_property(d->prop, proplist, name);
-
- if (d->method(propval, &d->arg)) {
- if (data != NULL)
- *data = &d->data;
-
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-static void cards_free(struct pa_classify_card *cards)
-{
- struct pa_classify_card_def *d;
-
- if (cards) {
- for (d = cards->defs; d->type; d++) {
- pa_xfree((void *)d->type);
- pa_xfree((void *)d->data.profile);
-
- if (d->method == pa_classify_method_matches)
- regfree(&d->arg.rexp);
- else
- pa_xfree((void *)d->arg.string);
- }
-
- pa_xfree(cards);
- }
-}
-
-static void cards_add(struct pa_classify_card **p_cards, char *type,
- enum pa_classify_method method, char *arg,
- char *profile, uint32_t flags)
-{
- struct pa_classify_card *cards;
- struct pa_classify_card_def *d;
- size_t newsize;
- char *method_name;
-
- pa_assert(p_cards);
- pa_assert_se((cards = *p_cards));
-
- newsize = sizeof(*cards) + sizeof(cards->defs[0]) * (cards->ndef + 1);
-
- cards = *p_cards = pa_xrealloc(cards, newsize);
-
- d = cards->defs + cards->ndef;
-
- memset(d+1, 0, sizeof(cards->defs[0]));
-
- d->type = pa_xstrdup(type);
-
- d->data.profile = profile ? pa_xstrdup(profile) : NULL;
- d->data.flags = flags;
-
- switch (method) {
-
- case pa_method_equals:
- method_name = "equals";
- d->method = pa_classify_method_equals;
- d->arg.string = pa_xstrdup(arg);
- break;
-
- case pa_method_startswith:
- method_name = "startswidth";
- d->method = pa_classify_method_startswith;
- d->arg.string = pa_xstrdup(arg);
- break;
-
- case pa_method_matches:
- method_name = "matches";
- if (regcomp(&d->arg.rexp, arg, 0) == 0) {
- d->method = pa_classify_method_matches;
- break;
- }
- /* intentional fall trough */
-
- default:
- pa_log("%s: invalid card definition %s", __FUNCTION__, type);
- memset(d, 0, sizeof(*d));
- return;
- }
-
- cards->ndef++;
-
- pa_log_info("card '%s' added (%s|%s|%s|0x%04x)", type, method_name, arg,
- d->data.profile?d->data.profile:"", d->data.flags);
-}
-
-static int cards_classify(struct pa_classify_card_def *defs,
- char *name, char **profiles,
- uint32_t flag_mask, uint32_t flag_value,
- char *buf, int len)
-{
- struct pa_classify_card_def *d;
- int i,j;
- char *p;
- char *e;
- const char *s;
- int supports_profile;
-
- pa_assert(buf);
- pa_assert(len > 0);
-
- e = (p = buf) + len;
- p[0] = '\0';
- s = "";
-
- for (d = defs, i = 0; d->type; d++) {
- if (d->method(name, &d->arg)) {
- if (d->data.profile == NULL)
- supports_profile = TRUE;
- else {
- for (j = 0, supports_profile = FALSE; profiles[j]; j++) {
- if (!strcmp(d->data.profile, profiles[j])) {
- supports_profile = TRUE;
- break;
- }
- }
- }
-
- if (supports_profile && (d->data.flags & flag_mask) == flag_value){
- p += snprintf(p, (size_t)(e-p), "%s%s", s, d->type);
- s = " ";
-
- if (p > e) {
- pa_log("%s: %s() buffer overflow", __FILE__, __FUNCTION__);
- *buf = '\0';
- p = e;
- break;
- }
- }
- }
- }
-
- return (e - p);
-}
-
-static int card_is_typeof(struct pa_classify_card_def *defs, char *name,
- char *type, struct pa_classify_card_data **data)
-{
- struct pa_classify_card_def *d;
-
- for (d = defs; d->type; d++) {
- if (!strcmp(type, d->type)) {
- if (d->method(name, &d->arg)) {
- if (data != NULL)
- *data = &d->data;
-
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-static int port_device_is_typeof(struct pa_classify_device_def *defs,
- char *name, const char *type,
- struct pa_classify_device_data **data)
-{
- struct pa_classify_device_def *d;
-
- for (d = defs; d->type; d++) {
- if (pa_streq(type, d->type)) {
- if (d->data.ports && pa_hashmap_get(d->data.ports, name)) {
- if (data != NULL)
- *data = &d->data;
-
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-char *get_property(char *propname, pa_proplist *proplist, char *name)
-{
- char *propval = NULL;
-
- if (propname != NULL && proplist != NULL && name != NULL) {
- if (!strcmp(propname, "name"))
- propval = name;
- else
- propval = (char *)pa_proplist_gets(proplist, propname);
- }
-
- if (propval == NULL || propval[0] == '\0')
- propval = (char *)"<unknown>";
-
- return propval;
-}
-
-int pa_classify_method_equals(const char *string,
- union pa_classify_arg *arg)
-{
- int found;
-
- if (!string || !arg || !arg->string)
- found = FALSE;
- else
- found = !strcmp(string, arg->string);
-
- return found;
-}
-
-int pa_classify_method_startswith(const char *string,
- union pa_classify_arg *arg)
-{
- int found;
-
- if (!string || !arg || !arg->string)
- found = FALSE;
- else
- found = !strncmp(string, arg->string, strlen(arg->string));
-
- return found;
-}
-
-int pa_classify_method_matches(const char *string,
- union pa_classify_arg *arg)
-{
-#define MAX_MATCH 5
-
- regmatch_t m[MAX_MATCH];
- regoff_t end;
- int found;
-
- found = FALSE;
-
- if (string && arg) {
- if (regexec(&arg->rexp, string, MAX_MATCH, m, 0) == 0) {
- end = strlen(string);
-
- if (m[0].rm_so == 0 && m[0].rm_eo == end && m[1].rm_so == -1)
- found = TRUE;
- }
- }
-
-
- return found;
-
-#undef MAX_MATCH
-}
-
-int pa_classify_method_true(const char *string,
- union pa_classify_arg *arg)
-{
- (void)string;
- (void)arg;
-
- return TRUE;
-}
-
-static const char *method_str(enum pa_classify_method method)
-{
- switch (method) {
- default:
- case pa_method_unknown: return "unknown";
- case pa_method_equals: return "equals";
- case pa_method_startswith: return "startswith";
- case pa_method_matches: return "matches";
- case pa_method_true: return "true";
- }
-}
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef fooclassifyfoo
-#define fooclassifyfoo
-
-#include <sys/types.h>
-#include <regex.h>
-
-#include "userdata.h"
-
-#define PA_POLICY_PID_HASH_BITS 6
-#define PA_POLICY_PID_HASH_MAX (1 << PA_POLICY_PID_HASH_BITS)
-#define PA_POLICY_PID_HASH_MASK (PA_POLICY_PID_HASH_MAX - 1)
-
-/* card flags */
-#define PA_POLICY_DISABLE_NOTIFY (1UL << 0)
-
-/* stream flags */
-#define PA_POLICY_LOCAL_ROUTE (1UL << 0)
-#define PA_POLICY_LOCAL_MUTE (1UL << 1)
-#define PA_POLICY_LOCAL_VOLMAX (1UL << 2)
-
-struct pa_sink;
-struct pa_source;
-struct pa_sink_input;
-struct pa_sink_input_new_data;
-struct pa_card;
-
-enum pa_classify_method {
- pa_method_unknown = 0,
- pa_method_min = pa_method_unknown,
- pa_method_equals,
- pa_method_startswith,
- pa_method_matches,
- pa_method_true,
- pa_method_max
-};
-
-union pa_classify_arg {
- const char *string;
- regex_t rexp;
-};
-
-struct pa_classify_pid_hash {
- struct pa_classify_pid_hash *next;
- pid_t pid; /* process id (or parent process id) */
- /* for stream classification */
- char *prop; /* stream property, if any */
- struct {
- enum pa_classify_method type;
- int (*func)(const char *,union pa_classify_arg *);
- } method;
- struct {
- char *def;
- union pa_classify_arg value;
- } arg; /* argument */
- char *group; /* policy group name */
-};
-
-struct pa_classify_stream_def {
- struct pa_classify_stream_def *next;
- /* for stream classification */
- char *prop; /* stream property */
- int (*method)(const char *,
- union pa_classify_arg *);
- union pa_classify_arg arg; /* argument */
- uid_t uid; /* user id, if any */
- char *exe; /* exe name, if any */
- char *clnam; /* client name, if any */
- char *group; /* policy group name */
- uint32_t flags; /* PA_POLICY_LOCAL_ROUTE |
- PA_POLICY_LOCAL_MUTE */
-};
-
-struct pa_classify_stream {
- struct pa_classify_pid_hash *pid_hash[PA_POLICY_PID_HASH_MAX];
- struct pa_classify_stream_def *defs;
-};
-
-
-struct pa_classify_port_entry {
- char *device_name; /* Sink or source name */
- char *port_name;
-};
-
-struct pa_classify_device_data {
- pa_hashmap *ports; /* Key: device name, value: pa_classify_port_entry. If
- * the device type doesn't require setting any ports,
- * this is NULL. */
- uint32_t flags; /* PA_POLICY_DISABLE_NOTIFY, etc */
-};
-
-struct pa_classify_device_def {
- const char *type; /* device type, e.g. ihf */
- /* for classification */
- char *prop; /* sink/source property */
- int (*method)(const char *,
- union pa_classify_arg *);
- union pa_classify_arg arg; /* argument */
- struct pa_classify_device_data data; /* data associated with device */
-};
-
-struct pa_classify_device {
- int ndef;
- struct pa_classify_device_def defs[1];
-};
-
-struct pa_classify_card_data {
- char *profile; /* name of profile */
- uint32_t flags; /* PA_POLICY_DISABLE_NOTIFY, etc */
-};
-
-struct pa_classify_card_def {
- const char *type; /* handled device name, e.g ihf */
- int (*method)(const char *,union pa_classify_arg *);
- union pa_classify_arg arg;
- struct pa_classify_card_data data; /* data associated with device 'type' */
-};
-
-struct pa_classify_card {
- int ndef;
- struct pa_classify_card_def defs[1];
-};
-
-struct pa_classify {
- struct pa_classify_stream streams;
- struct pa_classify_device *sinks;
- struct pa_classify_device *sources;
- struct pa_classify_card *cards;
-};
-
-
-struct pa_classify *pa_classify_new(struct userdata *);
-void pa_classify_free(struct pa_classify *);
-void pa_classify_add_sink(struct userdata *, char *, char *,
- enum pa_classify_method, char *, pa_hashmap *,
- uint32_t);
-void pa_classify_add_source(struct userdata *, char *, char *,
- enum pa_classify_method, char *, pa_hashmap *,
- uint32_t);
-void pa_classify_add_card(struct userdata *, char *,
- enum pa_classify_method, char *, char *, uint32_t);
-void pa_classify_add_stream(struct userdata *, char *,enum pa_classify_method,
- char *, char *, uid_t, char *, char *,
- uint32_t, char *);
-
-void pa_classify_port_entry_free(struct pa_classify_port_entry *);
-
-void pa_classify_register_pid(struct userdata *, pid_t, char *,
- enum pa_classify_method, char *, char *);
-void pa_classify_unregister_pid(struct userdata *, pid_t, char *,
- enum pa_classify_method, char *);
-
-char *pa_classify_sink_input(struct userdata *, struct pa_sink_input *,
- uint32_t *);
-char *pa_classify_sink_input_by_data(struct userdata *,
- struct pa_sink_input_new_data *,
- uint32_t *);
-char *pa_classify_source_output(struct userdata *, struct pa_source_output *);
-char *pa_classify_source_output_by_data(struct userdata *,
- struct pa_source_output_new_data *);
-
-int pa_classify_sink(struct userdata *, struct pa_sink *,
- uint32_t, uint32_t, char *, int);
-int pa_classify_source(struct userdata *, struct pa_source *,
- uint32_t, uint32_t, char *, int);
-int pa_classify_card(struct userdata *, struct pa_card *,
- uint32_t, uint32_t, char *, int);
-
-int pa_classify_is_sink_typeof(struct userdata *, struct pa_sink *,
- const char *,
- struct pa_classify_device_data **);
-int pa_classify_is_source_typeof(struct userdata *, struct pa_source *,
- const char *,
- struct pa_classify_device_data **);
-int pa_classify_is_card_typeof(struct userdata *, struct pa_card *,
- char *, struct pa_classify_card_data **);
-
-/* The ports= option in the [device] section may contain multiple sinks or
- * sources of which port should be set. These two functions are used to find
- * out whether the port of the given sink or source should be set. */
-int pa_classify_is_port_sink_typeof(struct userdata *, struct pa_sink *,
- const char *,
- struct pa_classify_device_data **);
-int pa_classify_is_port_source_typeof(struct userdata *, struct pa_source *,
- const char *,
- struct pa_classify_device_data **);
-
-int pa_classify_method_equals(const char *, union pa_classify_arg *);
-int pa_classify_method_startswith(const char *, union pa_classify_arg *);
-int pa_classify_method_matches(const char *, union pa_classify_arg *);
-int pa_classify_method_true(const char *, union pa_classify_arg *);
-
-#endif
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <pulsecore/pulsecore-config.h>
-#include <pulse/def.h>
-
-#include "userdata.h"
-#include "client-ext.h"
-
-static void handle_client_events(pa_core *, pa_subscription_event_type_t,
- uint32_t, void *);
-
-static void handle_new_or_modified_client(struct userdata *,
- struct pa_client *);
-static void handle_removed_client(struct userdata *, uint32_t);
-
-static char *client_ext_dump(struct pa_client *, char *, int);
-
-static void client_ext_set_arg0(struct pa_client *client);
-
-struct pa_client_evsubscr *pa_client_ext_subscription(struct userdata *u)
-{
- struct pa_client_evsubscr *subscr;
- pa_subscription *events;
-
- pa_assert(u);
- pa_assert(u->core);
-
- events = pa_subscription_new(u->core, 1 << PA_SUBSCRIPTION_EVENT_CLIENT,
- handle_client_events, (void *)u);
-
-
- subscr = pa_xnew0(struct pa_client_evsubscr, 1);
-
- subscr->events = events;
-
- return subscr;
-}
-
-void pa_client_ext_subscription_free(struct pa_client_evsubscr *subscr)
-{
- if (subscr != NULL) {
- pa_subscription_free(subscr->events);
-
- pa_xfree(subscr);
- }
-}
-
-void pa_client_ext_discover(struct userdata *u)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_client *client;
-
- pa_assert(u);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->clients));
-
- while ((client = pa_idxset_iterate(idxset, &state, NULL)) != NULL)
- handle_new_or_modified_client(u, client);
-}
-
-char *pa_client_ext_name(struct pa_client *client)
-{
- const char *name;
-
- assert(client);
-
- name = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME);
-
- return (char *)name;
-}
-
-char *pa_client_ext_id(struct pa_client *client)
-{
- const char *id;
-
- assert(client);
-
- id = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_ID);
-
- return (char *)id;
-}
-
-pid_t pa_client_ext_pid(struct pa_client *client)
-{
- const char *pidstr;
- pid_t pid;
- char *e;
-
- assert(client);
-
- pid = 0;
- pidstr = pa_proplist_gets(client->proplist,PA_PROP_APPLICATION_PROCESS_ID);
-
- if (pidstr != NULL) {
- pid = strtoul(pidstr, &e, 10);
-
- if (*e != '\0')
- pid = 0;
- }
-
- return pid;
-}
-
-uid_t pa_client_ext_uid(struct pa_client *client)
-{
- const char *uidstr;
- uid_t uid;
- char *e;
-
- assert(client);
-
- uid = 0;
- uidstr = pa_proplist_gets(client->proplist,
- PA_PROP_APPLICATION_PROCESS_USER);
-
- if (uidstr != NULL) {
- uid = strtoul(uidstr, &e, 10);
-
- if (*e != '\0')
- uid = 0;
- }
-
- return uid;
-}
-
-char *pa_client_ext_exe(struct pa_client *client)
-{
- const char *exe;
-
- assert(client);
-
- exe = pa_proplist_gets(client->proplist,
- PA_PROP_APPLICATION_PROCESS_BINARY);
-
- return (char *)exe;
-}
-
-char *pa_client_ext_args(struct pa_client *client)
-{
- const char *args;
-
- assert(client);
-
- args = pa_proplist_gets(client->proplist,PA_PROP_APPLICATION_PROCESS_ARGS);
-
- return (char *)args;
-}
-
-
-char *pa_client_ext_arg0(struct pa_client *client)
-{
- const char *arg0;
-
- assert(client);
-
- arg0 = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_PROCESS_ARG0);
-
- if (arg0 == NULL)
- client_ext_set_arg0(client);
-
- return (char *)arg0;
-}
-
-
-static void handle_client_events(pa_core *c,pa_subscription_event_type_t t,
- uint32_t idx, void *userdata)
-{
- struct userdata *u = userdata;
- uint32_t et = t & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
- struct pa_client *client;
-
- pa_assert(u);
-
- switch (et) {
-
- case PA_SUBSCRIPTION_EVENT_NEW:
- if ((client = pa_idxset_get_by_index(c->clients, idx)) != NULL) {
- handle_new_or_modified_client(u, client);
- }
- break;
-
- case PA_SUBSCRIPTION_EVENT_CHANGE:
- if ((client = pa_idxset_get_by_index(c->clients, idx)) != NULL) {
- handle_new_or_modified_client(u, client);
- }
- break;
-
- case PA_SUBSCRIPTION_EVENT_REMOVE:
- handle_removed_client(u, idx);
- break;
-
- default:
- pa_log("%s: unknown client event type %d", __FILE__, et);
- break;
- }
-
-}
-
-static void handle_new_or_modified_client(struct userdata *u,
- struct pa_client *client)
-{
- uint32_t idx = client->index;
- char buf[1024];
-
- pa_log_debug("new/modified client (idx=%d) %s", idx,
- client_ext_dump(client, buf, sizeof(buf)));
-}
-
-static void handle_removed_client(struct userdata *u, uint32_t idx)
-{
- pa_log_debug("client removed (idx=%d)", idx);
-}
-
-
-static void client_ext_set_arg0(struct pa_client *client)
-{
- char path[256], arg0[1024];
- int fd, len;
- pid_t pid;
-
- if (!(pid = pa_client_ext_pid(client))) {
- /*
- application.process.id property is set not for all kinds
- of pulseaudio clients, and not right after a client creation
- */
- pa_log_debug("no pid property for client %u, skip it", client->index);
- return;
- }
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fd = open(path, O_RDONLY)) < 0) {
- pa_log("%s: Can't obtain command line", __FILE__);
- return;
- }
-
-
- for (;;) {
- if ((len = read(fd, arg0, sizeof(arg0)-1)) < 0) {
- if (errno == EINTR)
- continue;
- else {
- arg0[0] = '\0';
- break;
- }
- }
-
- arg0[len] = '\0';
- break;
- }
-
- close(fd);
-
- pa_proplist_sets(client->proplist, PA_PROP_APPLICATION_PROCESS_ARG0, arg0);
-}
-
-
-#if 0
-static void client_ext_set_args(struct pa_client *client)
-{
-#if 0
- char path[256];
- char args[ARG_MAX];
- int argc;
- char *argv[1024];
- int fd, len;
- char *p, *e;
- int i, offs;
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", ext->pid);
-
- if ((fd = open(path, O_RDONLY)) < 0) {
- pa_log("%s: Can't obtain command line", __FILE__);
- return;
- }
-
- for (;;) {
- if ((len = read(fd, args, sizeof(args)-1)) < 0) {
- if (errno == EINTR)
- continue;
- else
- return;
- }
-
- args[len] = '\0';
-
- break;
- }
-
- for (e = (p = args) + len, argc = 0; argc < 1024 && p < e; argc++) {
- argv[argc] = p;
-
- while (*p++ && p < e)
- ;
- }
-
- p = pa_xmalloc((argc * sizeof(char *)) + len);
-
- memcpy(p, argv, (argc * sizeof(char *)));
- memcpy(p + (argc * sizeof(char *)), args, len);
-
- ext->argc = argc;
- ext->argv = (char **)p;
-
- offs = (p + (argc * sizeof(char *))) - args;
-
- for (i = 0; i < argc; i++)
- ext->argv[i] += offs;
-#endif
-}
-#endif
-
-
-static char *client_ext_dump(struct pa_client *client, char *buf, int len)
-{
- const char *name;
- const char *id;
- pid_t pid;
- uid_t uid;
- const char *exe;
- const char *args, *arg0;
-
- if (client == NULL)
- *buf = '\0';
- else {
- name = pa_client_ext_name(client);
- id = pa_client_ext_id(client);
- pid = pa_client_ext_pid(client);
- uid = pa_client_ext_uid(client);
- exe = pa_client_ext_exe(client);
- args = pa_client_ext_args(client);
- arg0 = pa_client_ext_arg0(client);
-
- if (!name) name = "<noname>";
- if ( !id ) id = "<noid>";
- if (!exe ) exe = "<noexe>";
- if (!args) args = "<noargs>";
- if (!arg0) arg0 = "<noarg>";
-
- snprintf(buf, len,
- "(%s|%s|%d|%d|%s|%s|%s)", name,id, pid, uid, exe,arg0,args);
- }
-
- return buf;
-}
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef fooclientextfoo
-#define fooclientextfoo
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <pulsecore/client.h>
-#include <pulsecore/core-subscribe.h>
-
-#include "userdata.h"
-
-struct pa_client;
-
-struct pa_client_evsubscr {
- pa_subscription *events;
-};
-
-struct pa_client_evsubscr *pa_client_ext_subscription(struct userdata *);
-void pa_client_ext_subscription_free(struct pa_client_evsubscr *);
-void pa_client_ext_discover(struct userdata *);
-char *pa_client_ext_name(struct pa_client *);
-char *pa_client_ext_id(struct pa_client *);
-pid_t pa_client_ext_pid(struct pa_client *);
-uid_t pa_client_ext_uid(struct pa_client *);
-char *pa_client_ext_exe(struct pa_client *);
-char *pa_client_ext_args(struct pa_client *);
-char *pa_client_ext_arg0(struct pa_client *);
-
-
-#endif
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <string.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <errno.h>
-
-#ifndef __USE_ISOC99
-#define __USE_ISOC99
-#include <ctype.h>
-#undef __USE_ISOC99
-#else
-#include <ctype.h>
-#endif
-
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/log.h>
-
-#include "config-file.h"
-#include "policy-group.h"
-#include "classify.h"
-#include "context.h"
-
-#define DEFAULT_CONFIG_FILE "policy.conf"
-#define DEFAULT_CONFIG_DIRECTORY "/etc/pulse/xpolicy.conf.d"
-
-enum section_type {
- section_unknown = 0,
- section_group,
- section_device,
- section_card,
- section_stream,
- section_context,
- section_max
-};
-
-enum device_class {
- device_unknown = 0,
- device_sink,
- device_source,
- device_max
-};
-
-
-#define PROPERTY_ACTION_COMMON \
- enum pa_policy_object_type objtype; /* eg. sink, source, sink-input etc */\
- enum pa_classify_method method; /* obj.name based classif. method */\
- char *arg; /* obj.name based classif. argument */\
- char *propnam /* name of property */
-
-struct anyprop {
- PROPERTY_ACTION_COMMON;
-};
-
-struct setprop { /* set property of a PA object */
- PROPERTY_ACTION_COMMON;
- enum pa_policy_value_type valtype; /* type of prop.value to be set */
- char *valarg; /* arg for value setting, if any */
-};
-
-struct delprop { /* delete property of a PA object */
- PROPERTY_ACTION_COMMON;
-};
-
-
-struct ctxact { /* context rule actions */
- enum pa_policy_action_type type; /* context action type */
- int lineno; /* reference to config file */
- union {
- struct anyprop anyprop; /* common for all prop.operation */
- struct setprop setprop; /* setting property of an object */
- struct delprop delprop; /* deleting property of an object */
- };
-};
-
-
-struct groupdef {
- char *name;
- char *sink;
- char *source;
- uint32_t flags;
-};
-
-struct devicedef {
- enum device_class class;
- char *type;
- char *prop;
- enum pa_classify_method method;
- char *arg;
- pa_hashmap *ports; /* Key: device name, value:
- * pa_classify_port_entry. */
- uint32_t flags;
-};
-
-struct carddef {
- char *type;
- enum pa_classify_method method;
- char *arg;
- char *profile;
- uint32_t flags;
-};
-
-struct streamdef {
- char *prop; /* stream property to classify it */
- enum pa_classify_method method; /* property based classification method */
- char *arg; /* param for prop.based classification */
- char *clnam; /* client's name in pulse audio */
- uid_t uid; /* client's user id */
- char *exe; /* the executable name (i.e. argv[0]) */
- char *group; /* group name the stream belong to */
- uint32_t flags; /* stream flags */
- char *port; /* port for local routing, if any */
-};
-
-
-struct contextdef {
- char *varnam; /* context variable name */
- enum pa_classify_method method; /* context value based classification */
- char *arg; /* param for ctx.value classification */
- int nact; /* number of actions */
- struct ctxact *acts; /* array of actions */
-};
-
-struct section {
- enum section_type type;
- union {
- void *any;
- struct groupdef *group;
- struct devicedef *device;
- struct carddef *card;
- struct streamdef *stream;
- struct contextdef *context;
- } def;
-};
-
-
-static int preprocess_buffer(int, char *, char *);
-
-static int section_header(int, char *, enum section_type *);
-static int section_open(struct userdata *, enum section_type,struct section *);
-static int section_close(struct userdata *, struct section *);
-
-static int groupdef_parse(int, char *, struct groupdef *);
-static int devicedef_parse(int, char *, struct devicedef *);
-static int carddef_parse(int, char *, struct carddef *);
-static int streamdef_parse(int, char *, struct streamdef *);
-static int contextdef_parse(int, char *, struct contextdef *);
-
-static int deviceprop_parse(int, enum device_class,char *,struct devicedef *);
-static int ports_parse(int, const char *, struct devicedef *);
-static int streamprop_parse(int, char *, struct streamdef *);
-static int contextval_parse(int, char *, struct contextdef *);
-static int contextsetprop_parse(int, char *, struct contextdef *);
-static int contextdelprop_parse(int, char *, struct contextdef *);
-static int contextanyprop_parse(int, char *, char *, struct anyprop *);
-static int cardname_parse(int, char *, struct carddef *);
-static int flags_parse(int, char *, enum section_type, uint32_t *);
-static int valid_label(int, char *);
-
-#ifndef HAS_SPLIT_STRV
-static char **pa_split_strv(const char *, const char *);
-#endif
-
-int pa_policy_parse_config_file(struct userdata *u, const char *cfgfile)
-{
-#define BUFSIZE 512
-
- FILE *f;
- char cfgpath[PATH_MAX];
- char ovrpath[PATH_MAX];
- char *path;
- char buf[BUFSIZE];
- char line[BUFSIZE];
- int lineno;
- enum section_type newsect;
- struct section section;
- struct groupdef *grdef;
- struct devicedef *devdef;
- struct carddef *carddef;
- struct streamdef *strdef;
- struct contextdef *ctxdef;
- int success;
-
- pa_assert(u);
-
- if (!cfgfile)
- cfgfile = DEFAULT_CONFIG_FILE;
-
- pa_policy_file_path(cfgfile, cfgpath, PATH_MAX);
- snprintf(ovrpath, PATH_MAX, "%s.override", cfgpath);
-
- if ((f = fopen(ovrpath,"r")) != NULL)
- path = ovrpath;
- else if ((f = fopen(cfgpath, "r")) != NULL)
- path = cfgpath;
- else {
- pa_log("Can't open config file '%s': %s", cfgpath, strerror(errno));
- return 0;
- }
-
- pa_log_info("parsing config file '%s'", path);
-
- success = TRUE; /* assume successful operation */
-
- memset(§ion, 0, sizeof(section));
-
- for (errno = 0, lineno = 1; fgets(buf, BUFSIZE, f) != NULL; lineno++) {
- if (preprocess_buffer(lineno, buf, line) < 0)
- break;
-
- if (*line == '\0')
- continue;
-
- if (section_header(lineno, line, &newsect)) {
- if (section_close(u, §ion) < 0)
- success = FALSE;
-
- section.type = newsect;
-
- if (section_open(u, newsect, §ion) < 0)
- success = FALSE;
- }
- else {
- switch (section.type) {
-
- case section_group:
- grdef = section.def.group;
-
- if (groupdef_parse(lineno, line, grdef) < 0)
- success = FALSE;
-
- break;
-
- case section_device:
- devdef = section.def.device;
-
- if (devicedef_parse(lineno, line, devdef) < 0)
- success = FALSE;
-
- break;
-
- case section_card:
- carddef = section.def.card;
-
- if (carddef_parse(lineno, line, carddef) < 0)
- success = FALSE;
-
- break;
-
- case section_stream:
- strdef = section.def.stream;
-
- if (streamdef_parse(lineno, line, strdef) < 0)
- success = FALSE;
-
- break;
-
- case section_context:
- ctxdef = section.def.context;
-
- if (contextdef_parse(lineno, line, ctxdef) < 0)
- success = FALSE;
-
- break;
-
- default:
- break;
-
- }
- }
- }
-
- section_close(u, §ion);
- endpwent();
-
- if (fclose(f) != 0) {
- pa_log("Can't close config file '%s': %s", path, strerror(errno));
- }
-
- return success;
-}
-
-int pa_policy_parse_files_in_configdir(struct userdata *u, const char *cfgdir)
-{
-#define BUFSIZE 512
-
- DIR *d;
- FILE *f;
- struct dirent *e;
- const char *p;
- char *q;
- int l;
- char cfgpath[PATH_MAX];
- char **overrides;
- int noverride;
- char buf[BUFSIZE];
- char line[BUFSIZE];
- int lineno;
- enum section_type newsect;
- struct section section;
- int i;
-
- pa_assert(u);
-
- if (!cfgdir)
- cfgdir = DEFAULT_CONFIG_DIRECTORY;
-
- pa_log_info("policy config directory is '%s'", cfgdir);
-
- overrides = NULL;
- noverride = 0;
-
- if ((d = opendir(cfgdir)) != NULL) {
- while ((e = readdir(d)) != NULL) {
- if ((p = strstr(e->d_name, ".conf.override")) == NULL || p[14])
- continue; /* does not match '*.conf.override' */
-
- l = (p + 5) - e->d_name; /* length of '*.conf' */
- q = pa_xmalloc(l + 1);
- strncpy(q, e->d_name, l);
- q[l] = '\0';
-
- overrides = pa_xrealloc(overrides, (noverride+1) * sizeof(char *));
- overrides[noverride++] = q;
- }
- closedir(d);
- }
-
- if ((d = opendir(cfgdir)) == NULL)
- pa_log("Can't find config directory '%s'", cfgdir);
- else {
- for (p = cfgdir, q = cfgpath; (q-cfgpath < PATH_MAX) && *p; p++,q++)
- *q = *p;
- if (q == cfgpath || q[-1] != '/')
- *q++ = '/';
- l = (cfgpath + PATH_MAX) - q;
-
- errno = 0;
-
- while (l > 1 && (e = readdir(d)) != NULL) {
- if ((p = strstr(e->d_name, ".conf")) != NULL && !p[5]) {
- for (i = 0; i < noverride; i++) {
- if (!strcmp(e->d_name, overrides[i]))
- break;
- }
-
- if (i < noverride) {
- strncpy(q, e->d_name, l);
- cfgpath[PATH_MAX-1] = '\0';
- pa_log_info("skip overriden config file '%s'", cfgpath);
- continue;
- }
- }
- else if ((p = strstr(e->d_name,".conf.override")) == NULL || p[14])
- continue; /* neither '*.conf' nor '*.conf.override' */
-
- strncpy(q, e->d_name, l);
- cfgpath[PATH_MAX-1] = '\0';
-
- pa_log_info("parsing config file '%s'", cfgpath);
-
-
- if ((f = fopen(cfgpath, "r")) == NULL) {
- pa_log("Can't open config file '%s': %s",
- cfgpath, strerror(errno));
- continue;
- }
-
- memset(§ion, 0, sizeof(section));
-
- for (errno = 0, lineno = 1; fgets(buf, BUFSIZE, f); lineno++) {
-
- if (preprocess_buffer(lineno, buf, line) < 0)
- break;
-
- if (*line == '\0')
- continue;
-
- if (section_header(lineno, line, &newsect)) {
- section_close(u, §ion);
-
- if ((section.type = newsect) == section_stream)
- section_open(u, newsect, §ion);
- else {
- pa_log("line %d: only [stream] section is allowed",
- lineno);
- }
- }
- else {
- switch (section.type) {
- case section_stream:
- streamdef_parse(lineno, line, section.def.stream);
- break;
- default:
- break;
- }
- }
- } /* for fgets() */
-
- section_close(u, §ion);
- endpwent();
-
- if (fclose(f) != 0) {
- pa_log("Can't close config file '%s': %s",
- cfgpath, strerror(errno));
- }
- } /* while readdir() */
-
- closedir(d);
-
- } /* if opendir() */
-
-
- for (i = 0; i < noverride; i++)
- pa_xfree(overrides[i]);
-
- pa_xfree(overrides);
-
-
- return TRUE;
-}
-
-static int preprocess_buffer(int lineno, char *inbuf, char *outbuf)
-{
- char c, *p, *q;
- int quote;
- int sts = 0;
-
- for (quote = 0, p = inbuf, q = outbuf; (c = *p) != '\0'; p++) {
- if (!quote && isblank(c))
- continue;
-
- if (c == '\n' || (!quote && c == '#'))
- break;
-
- if (c == '"') {
- quote ^= 1;
- continue;
- }
-
- if (c < 0x20) {
- pa_log("Illegal character 0x%02x in line %d", c, lineno);
- sts = -1;
- errno = EILSEQ;
- break;
- }
-
- *q++ = c;
- }
- *q = '\0';
-
- if (quote) {
- pa_log("unterminated quoted string '%s' in line %d", inbuf, lineno);
- }
-
- return sts;
-}
-
-
-static int section_header(int lineno, char *line, enum section_type *type)
-{
- int is_section;
-
- if (line[0] != '[')
- is_section = 0;
- else {
- is_section = 1;
-
- if (!strcmp(line, "[group]"))
- *type = section_group;
- else if (!strcmp(line,"[device]"))
- *type = section_device;
- else if (!strcmp(line,"[card]"))
- *type = section_card;
- else if (!strcmp(line, "[stream]"))
- *type = section_stream;
- else if (!strcmp(line, "[context-rule]"))
- *type = section_context;
- else {
- *type = section_unknown;
- pa_log("Invalid section type '%s' in line %d", line, lineno);
- }
- }
-
- return is_section;
-}
-
-static int section_open(struct userdata *u, enum section_type type,
- struct section *sec)
-{
- int status;
-
- if (sec == NULL)
- status = -1;
- else {
- switch (type) {
-
- case section_group:
- sec->def.group = pa_xnew0(struct groupdef, 1);
- status = 0;
- break;
-
- case section_device:
- sec->def.device = pa_xnew0(struct devicedef, 1);
- status = 0;
- break;
-
- case section_card:
- sec->def.card = pa_xnew0(struct carddef, 1);
- status = 0;
- break;
-
- case section_stream:
- sec->def.stream = pa_xnew0(struct streamdef, 1);
- sec->def.stream->uid = -1;
- status = 0;
- break;
-
- case section_context:
- sec->def.context = pa_xnew0(struct contextdef, 1);
- sec->def.context->method = pa_method_true;
- status = 0;
- break;
-
- default:
- type = section_unknown;
- sec->def.any = NULL;
- status = -1;
- break;
- }
-
- sec->type = type;
- }
-
- return status;
-}
-
-static int section_close(struct userdata *u, struct section *sec)
-{
- struct groupdef *grdef;
- struct devicedef *devdef;
- struct carddef *carddef;
- struct streamdef *strdef;
- struct contextdef *ctxdef;
- struct ctxact *act;
- struct pa_policy_context_rule *rule;
- struct setprop *setprop;
- struct delprop *delprop;
- int i;
- int status;
-
- if (sec == NULL)
- status = -1;
- else {
- switch (sec->type) {
-
- case section_group:
- status = 0;
- grdef = sec->def.group;
-
- pa_policy_group_new(u, grdef->name, grdef->sink,
- grdef->source, grdef->flags);
-
- pa_xfree(grdef->name);
- pa_xfree(grdef->sink);
- pa_xfree(grdef->source);
- pa_xfree(grdef);
-
- break;
-
- case section_device:
- status = 0;
- devdef = sec->def.device;
-
- switch (devdef->class) {
-
- case device_sink:
- /* All devdef values are deep copied. */
- pa_classify_add_sink(u, devdef->type,
- devdef->prop, devdef->method, devdef->arg,
- devdef->ports, devdef->flags);
- break;
-
- case device_source:
- /* All devdef values are deep copied. */
- pa_classify_add_source(u, devdef->type,
- devdef->prop, devdef->method,
- devdef->arg, devdef->ports,
- devdef->flags);
- break;
-
- default:
- break;
- }
-
- if (devdef->ports) {
- struct pa_classify_port_entry *port;
-
- while ((port = pa_hashmap_steal_first(devdef->ports)))
- pa_classify_port_entry_free(port);
-
- pa_hashmap_free(devdef->ports, NULL, NULL);
- }
-
- pa_xfree(devdef->type);
- pa_xfree(devdef->prop);
- pa_xfree(devdef->arg);
- pa_xfree(devdef);
-
- break;
-
- case section_card:
- status = 0;
- carddef = sec->def.card;
-
- pa_classify_add_card(u, carddef->type, carddef->method,
- carddef->arg, carddef->profile,
- carddef->flags);
-
- pa_xfree(carddef->type);
- pa_xfree(carddef->arg);
- pa_xfree(carddef->profile);
- pa_xfree(carddef);
-
- break;
-
- case section_stream:
- status = 0;
- strdef = sec->def.stream;
-
- if (strdef->port)
- strdef->flags |= PA_POLICY_LOCAL_ROUTE;
-
- pa_classify_add_stream(u, strdef->prop,strdef->method,strdef->arg,
- strdef->clnam, strdef->uid, strdef->exe,
- strdef->group, strdef->flags, strdef->port);
-
- pa_xfree(strdef->prop);
- pa_xfree(strdef->arg);
- pa_xfree(strdef->clnam);
- pa_xfree(strdef->exe);
- pa_xfree(strdef->group);
- pa_xfree(strdef->port);
- pa_xfree(strdef);
-
- break;
-
- case section_context:
- status = 0;
- ctxdef = sec->def.context;
-
- rule = pa_policy_context_add_property_rule(u, ctxdef->varnam,
- ctxdef->method,
- ctxdef->arg);
-
- for (i = 0; i < ctxdef->nact; i++) {
- act = ctxdef->acts + i;
-
- switch (act->type) {
-
- case pa_policy_set_property:
- setprop = &act->setprop;
-
- if (rule != NULL) {
- pa_policy_context_add_property_action(
- rule, act->lineno,
- setprop->objtype,
- setprop->method,
- setprop->arg,
- setprop->propnam,
- setprop->valtype,
- setprop->valarg
- );
- }
-
- pa_xfree(setprop->arg);
- pa_xfree(setprop->propnam);
- pa_xfree(setprop->valarg);
-
- break;
-
- case pa_policy_delete_property:
- delprop = &act->delprop;
-
- if (rule != NULL) {
- pa_policy_context_delete_property_action(
- rule, act->lineno,
- delprop->objtype,
- delprop->method,
- delprop->arg,
- delprop->propnam
- );
- }
-
- pa_xfree(delprop->arg);
- pa_xfree(delprop->propnam);
-
- break;
-
- default:
- break;
- }
- }
-
- pa_xfree(ctxdef->varnam);
- pa_xfree(ctxdef->arg);
- pa_xfree(ctxdef->acts);
- pa_xfree(ctxdef);
-
- break;
-
- default:
- status = 0;
- break;
- }
-
- sec->type = section_unknown;
- sec->def.any = NULL;
- }
-
- return status;
-}
-
-
-static int groupdef_parse(int lineno, char *line, struct groupdef *grdef)
-{
- int sts = 0;
- char *end;
- char *comma;
- char *fldef;
- char *flname;
- int len;
- uint32_t flags;
-
- if (grdef == NULL)
- sts = -1;
- else {
- if (!strncmp(line, "name=", 5)) {
- if (!valid_label(lineno, line+5))
- sts = -1;
- else
- grdef->name = pa_xstrdup(line+5);
- }
- else if (!strncmp(line, "sink=", 5)) {
- grdef->sink = pa_xstrdup(line+5);
- }
- else if (!strncmp(line, "source=", 7)) {
- grdef->source = pa_xstrdup(line+7);
- }
- else if (!strncmp(line, "flags=", 6)) {
- fldef = line + 6;
-
- if (fldef[0] == '\0') {
- sts = -1;
- pa_log("missing flag definition in line %d", lineno);
- }
- else {
- sts = 0;
-
- if (!strcmp(fldef, "client"))
- flags = PA_POLICY_GROUP_FLAGS_CLIENT;
- else if (!strcmp(fldef, "nopolicy"))
- flags = PA_POLICY_GROUP_FLAGS_NOPOLICY;
- else {
- flags = 0;
-
- for (flname = fldef; *flname; flname += len) {
- if ((comma = strchr(flname, ',')) == NULL)
- len = strlen(flname);
- else {
- *comma = '\0';
- len = (comma - flname) + 1;
- }
-
- if (!strcmp(flname, "set_sink"))
- flags |= PA_POLICY_GROUP_FLAG_SET_SINK;
- else if (!strcmp(flname, "set_source"))
- flags |= PA_POLICY_GROUP_FLAG_SET_SOURCE;
- else if (!strcmp(flname, "route_audio"))
- flags |= PA_POLICY_GROUP_FLAG_ROUTE_AUDIO;
- else if (!strcmp(flname, "limit_volume"))
- flags |= PA_POLICY_GROUP_FLAG_LIMIT_VOLUME;
- else if (!strcmp(flname, "cork_stream"))
- flags |= PA_POLICY_GROUP_FLAG_CORK_STREAM;
- else if (!strcmp(flname, "mute_by_route"))
- flags |= PA_POLICY_GROUP_FLAG_MUTE_BY_ROUTE;
- else {
- pa_log("invalid flag '%s' in line %d",
- flname, lineno);
- sts = -1;
- break;
- }
- } /* for */
- }
-
- if (sts >= 0) {
- grdef->flags = flags;
- }
- }
- }
- else {
- if ((end = strchr(line, '=')) == NULL) {
- pa_log("invalid definition '%s' in line %d", line, lineno);
- }
- else {
- *end = '\0';
- pa_log("invalid key value '%s' in line %d", line, lineno);
- }
- sts = -1;
- }
- }
-
- return sts;
-}
-
-static int devicedef_parse(int lineno, char *line, struct devicedef *devdef)
-{
- int sts;
- char *end;
-
- if (devdef == NULL)
- sts = -1;
- else {
- sts = 0;
-
- if (!strncmp(line, "type=", 5)) {
- devdef->type = pa_xstrdup(line+5);
- }
- else if (!strncmp(line, "sink=", 5)) {
- sts = deviceprop_parse(lineno, device_sink, line+5, devdef);
- }
- else if (!strncmp(line, "source=", 7)) {
- sts = deviceprop_parse(lineno, device_source, line+7, devdef);
- }
- else if (!strncmp(line, "ports=", 6)) {
- sts = ports_parse(lineno, line+6, devdef);
- }
- else if (!strncmp(line, "flags=", 6)) {
- sts = flags_parse(lineno, line+6, section_device, &devdef->flags);
- }
- else {
- if ((end = strchr(line, '=')) == NULL) {
- pa_log("invalid definition '%s' in line %d", line, lineno);
- }
- else {
- *end = '\0';
- pa_log("invalid key value '%s' in line %d", line, lineno);
- }
- sts = -1;
- }
- }
-
- return sts;
-}
-
-static int carddef_parse(int lineno, char *line, struct carddef *carddef)
-{
- int sts;
- char *end;
-
- if (carddef == NULL)
- sts = -1;
- else {
- sts = 0;
-
- if (!strncmp(line, "type=", 5)) {
- carddef->type = pa_xstrdup(line+5);
- }
- else if (!strncmp(line, "name=", 5)) {
- sts = cardname_parse(lineno, line+5, carddef);
- }
- else if (!strncmp(line, "profile=", 8)) {
- carddef->profile = pa_xstrdup(line+8);
- }
- else if (!strncmp(line, "flags=", 6)) {
- sts = flags_parse(lineno, line+6, section_card, &carddef->flags);
- }
- else {
- if ((end = strchr(line, '=')) == NULL) {
- pa_log("invalid definition '%s' in line %d", line, lineno);
- }
- else {
- *end = '\0';
- pa_log("invalid key value '%s' in line %d", line, lineno);
- }
- sts = -1;
- }
- }
-
- return sts;
-}
-
-static int streamdef_parse(int lineno, char *line, struct streamdef *strdef)
-{
- int sts;
- char *user;
- struct passwd *pwd;
- int uid;
- char *end;
-
- if (strdef == NULL)
- sts = -1;
- else {
- sts = 0;
-
- if (!strncmp(line, "name=", 5)) {
- strdef->prop = pa_xstrdup(PA_PROP_MEDIA_NAME);
- strdef->method = pa_method_equals;
- strdef->arg = pa_xstrdup(line+5);
- }
- else if (!strncmp(line, "property=", 9)) {
- sts = streamprop_parse(lineno, line+9, strdef);
- }
- else if (!strncmp(line, "client=", 7)) {
- strdef->clnam = pa_xstrdup(line+7);
- }
- else if (!strncmp(line, "user=", 5)) {
- user = line+5;
- uid = strtol(user, &end, 10);
-
- if (end == user || *end != '\0' || uid < 0) {
- uid = -1;
- setpwent();
-
- while ((pwd = getpwent()) != NULL) {
- if (!strcmp(user, pwd->pw_name)) {
- uid = pwd->pw_uid;
- break;
- }
- }
-
- if (uid < 0) {
- pa_log("invalid user '%s' in line %d", user, lineno);
- sts = -1;
- }
- }
-
- strdef->uid = (uid_t) uid;
- }
- else if (!strncmp(line, "exe=", 4)) {
- strdef->exe = pa_xstrdup(line+4);
- }
- else if (!strncmp(line, "group=", 6)) {
- strdef->group = pa_xstrdup(line+6);
- }
- else if (!strncmp(line, "flags=", 6)) {
- sts = flags_parse(lineno, line+6, section_stream, &strdef->flags);
- }
- else if (!strncmp(line, "port_if_active=", 15)) {
- strdef->port = pa_xstrdup(line+15);
- }
- else {
- if ((end = strchr(line, '=')) == NULL) {
- pa_log("invalid definition '%s' in line %d", line, lineno);
- }
- else {
- *end = '\0';
- pa_log("invalid key value '%s' in line %d", line, lineno);
- }
- sts = -1;
- }
- }
-
- return sts;
-}
-
-static int contextdef_parse(int lineno, char *line, struct contextdef *ctxdef)
-{
- int sts;
- char *end;
-
- if (ctxdef == NULL)
- sts = -1;
- else {
- sts = 0;
-
- if (!strncmp(line, "variable=", 9)) {
- ctxdef->varnam = pa_xstrdup(line+9);
- }
- else if (!strncmp(line, "value=", 6)) {
- sts = contextval_parse(lineno, line+6, ctxdef);
- }
- else if (!strncmp(line, "set-property=", 13)) {
- sts = contextsetprop_parse(lineno, line+13, ctxdef);
- }
- else if (!strncmp(line, "delete-property=", 16)) {
- sts = contextdelprop_parse(lineno, line+16, ctxdef);
- }
- else {
- if ((end = strchr(line, '=')) == NULL) {
- pa_log("invalid definition '%s' in line %d", line, lineno);
- }
- else {
- *end = '\0';
- pa_log("invalid key value '%s' in line %d", line, lineno);
- }
- sts = -1;
- }
- }
-
- return sts;
-}
-
-static int deviceprop_parse(int lineno, enum device_class class,
- char *propdef, struct devicedef *devdef)
-{
- char *colon;
- char *at;
- char *prop;
- char *method;
- char *arg;
-
- if ((colon = strchr(propdef, ':')) == NULL) {
- pa_log("invalid definition '%s' in line %d", propdef, lineno);
- return -1;
- }
-
- *colon = '\0';
- arg = colon + 1;
-
- if ((at = strchr(propdef, '@')) == NULL) {
- prop = "name";
- method = propdef;
- }
- else {
- *at = '\0';
- prop = propdef;
- method = at + 1;
- }
-
- if (!strcmp(method, "equals"))
- devdef->method = pa_method_equals;
- else if (!strcmp(method, "startswith"))
- devdef->method = pa_method_startswith;
- else if (!strcmp(method, "matches"))
- devdef->method = pa_method_matches;
- else {
- pa_log("invalid method '%s' in line %d", method, lineno);
- return -1;
- }
-
- devdef->class = class;
- devdef->prop = pa_xstrdup(prop);
- devdef->arg = pa_xstrdup(arg);
-
- return 0;
-}
-
-static int ports_parse(int lineno, const char *portsdef,
- struct devicedef *devdef)
-{
-#if PULSEAUDIO_HAS_PORTS
- char **entries;
-
- if (devdef->ports) {
- struct pa_classify_port_entry *port;
-
- pa_log("Duplicate ports= line in line %d, using the last "
- "occurrence.", lineno);
-
- while ((port = pa_hashmap_steal_first(devdef->ports)))
- pa_classify_port_entry_free(port);
-
- pa_hashmap_free(devdef->ports, NULL, NULL);
- }
-
- devdef->ports = pa_hashmap_new(pa_idxset_string_hash_func,
- pa_idxset_string_compare_func);
-
- if ((entries = pa_split_strv(portsdef, ","))) {
- char *entry; /* This string has format "sinkname:portname". */
- int i = 0;
-
- while ((entry = entries[i++])) {
- struct pa_classify_port_entry *port;
- size_t entry_len;
- size_t colon_pos;
-
- if (!*entry) {
- pa_log_debug("Ignoring a redundant comma in line %d", lineno);
- continue;
- }
-
- entry_len = strlen(entry);
- colon_pos = strcspn(entry, ":");
-
- if (colon_pos == entry_len) {
- pa_log("Colon missing in port entry '%s' in line %d, ignoring "
- "the entry", entry, lineno);
- continue;
- } else if (colon_pos == 0) {
- pa_log("Empty device name in port entry '%s' in line %d, "
- "ignoring the entry", entry, lineno);
- continue;
- } else if (colon_pos == entry_len - 1) {
- pa_log("Empty port name in port entry '%s' in line %d, "
- "ignoring the entry", entry, lineno);
- continue;
- }
-
- port = pa_xnew(struct pa_classify_port_entry, 1);
- port->device_name = pa_xstrndup(entry, colon_pos);
- port->port_name = pa_xstrdup(entry + colon_pos + 1);
-
- if (pa_hashmap_put(devdef->ports, port->device_name, port) < 0) {
- pa_log("Duplicate device name in port entry '%s' in line %d, "
- "using the first occurrence", entry, lineno);
-
- pa_classify_port_entry_free(port);
- }
- }
-
- pa_xstrfreev(entries);
-
- } else
- pa_log_warn("Empty ports= definition in line %d", lineno);
-#endif
-
- return 0;
-}
-
-static int streamprop_parse(int lineno,char *propdef,struct streamdef *strdef)
-{
- char *colon;
- char *at;
- char *prop;
- char *method;
- char *arg;
-
- if ((colon = strchr(propdef, ':')) == NULL) {
- pa_log("invalid definition '%s' in line %d", propdef, lineno);
- return -1;
- }
-
- *colon = '\0';
- arg = colon + 1;
-
- if ((at = strchr(propdef, '@')) == NULL) {
- pa_log("invalid definition '%s' in line %d", propdef, lineno);
- return -1;
- }
-
- *at = '\0';
- prop = propdef;
- method = at + 1;
-
- if (!strcmp(method, "equals"))
- strdef->method = pa_method_equals;
- else if (!strcmp(method, "startswith"))
- strdef->method = pa_method_startswith;
- else if (!strcmp(method, "matches"))
- strdef->method = pa_method_matches;
- else {
- pa_log("invalid method '%s' in line %d", method, lineno);
- return -1;
- }
-
- strdef->prop = pa_xstrdup(prop);
- strdef->arg = pa_xstrdup(arg);
-
- return 0;
-}
-
-static int contextval_parse(int lineno,char *valdef, struct contextdef *ctxdef)
-{
- char *colon;
- char *method;
- char *arg;
-
- if ((colon = strchr(valdef, ':')) == NULL) {
- pa_log("invalid definition '%s' in line %d", valdef, lineno);
- return -1;
- }
-
- *colon = '\0';
- method = valdef;
- arg = colon + 1;
-
- if (!strcmp(method, "equals"))
- ctxdef->method = pa_method_equals;
- else if (!strcmp(method, "startswith"))
- ctxdef->method = pa_method_startswith;
- else if (!strcmp(method, "matches"))
- ctxdef->method = strcmp(arg, "*") ? pa_method_matches : pa_method_true;
- else {
- pa_log("invalid method '%s' in line %d", method, lineno);
- return -1;
- }
-
- ctxdef->arg = (ctxdef->method == pa_method_true) ? NULL : pa_xstrdup(arg);
-
- return 0;
-}
-
-static int contextsetprop_parse(int lineno, char *setpropdef,
- struct contextdef *ctxdef)
-{
- size_t size;
- struct ctxact *act;
- struct setprop *setprop;
- struct anyprop *anyprop;
- char *comma1;
- char *comma2;
- char *objdef;
- char *propdef;
- char *valdef;
- char *valarg;
-
- /*
- * sink-name@startswidth:alsa,property:foo,value@constant:bar
- */
-
- size = sizeof(*act) * (ctxdef->nact + 1);
- act = (ctxdef->acts = pa_xrealloc(ctxdef->acts, size)) + ctxdef->nact;
-
- memset(act, 0, sizeof(*act));
- act->type = pa_policy_set_property;
- act->lineno = lineno;
-
- setprop = &act->setprop;
- anyprop = &act->anyprop;
-
- if ((comma1 = strchr(setpropdef, ',')) == NULL ||
- (comma2 = strchr(comma1 + 1, ',')) == NULL )
- {
- pa_log("invalid definition '%s' in line %d", setpropdef, lineno);
- return -1;
- }
-
- *comma1 = '\0';
- *comma2 = '\0';
-
- objdef = setpropdef;
- propdef = comma1 + 1;
- valdef = comma2 + 1;
-
- if (!strncmp(valdef, "value@constant:", 15)) {
- setprop->valtype = pa_policy_value_constant;
- valarg = valdef + 15;
- }
- else if (!strncmp(valdef, "value@copy-from-context", 23)) {
- setprop->valtype = pa_policy_value_copy;
- valarg = NULL;
- }
- else {
- pa_log("invalid value definition '%s' in line %d", valdef, lineno);
- return -1;
- }
-
- if (contextanyprop_parse(lineno, objdef, propdef, anyprop) < 0)
- return -1;
-
- setprop->valarg = valarg ? pa_xstrdup(valarg) : NULL;
-
- ctxdef->nact++;
-
- return 0;
-}
-
-static int contextdelprop_parse(int lineno, char *delpropdef,
- struct contextdef *ctxdef)
-{
- size_t size;
- struct ctxact *act;
- struct anyprop *anyprop;
- char *comma;
- char *objdef;
- char *propdef;
-
- /*
- * sink-name@startswidth:alsa,property:foo
- */
-
- size = sizeof(*act) * (ctxdef->nact + 1);
- act = (ctxdef->acts = pa_xrealloc(ctxdef->acts, size)) + ctxdef->nact;
-
- memset(act, 0, sizeof(*act));
- act->type = pa_policy_delete_property;
- act->lineno = lineno;
-
- anyprop = &act->anyprop;
-
- if ((comma = strchr(delpropdef, ',')) == NULL) {
- pa_log("invalid definition '%s' in line %d", delpropdef, lineno);
- return -1;
- }
-
- *comma = '\0';
-
- objdef = delpropdef;
- propdef = comma + 1;
-
- if (contextanyprop_parse(lineno, objdef, propdef, anyprop) < 0)
- return -1;
-
- ctxdef->nact++;
-
- return 0;
-}
-
-static int contextanyprop_parse(int lineno, char *objdef, char *propdef,
- struct anyprop *anyprop)
-{
- char *colon;
- char *method;
- char *arg;
- char *propnam;
-
- /*
- * objdef = "sink-name@startswidth:alsa"
- * propdef = "property:foo"
- */
- if (!strncmp(objdef, "module-name@", 12)) {
- anyprop->objtype = pa_policy_object_module;
- method = objdef + 12;
- }
- else if (!strncmp(objdef, "card-name@", 10)) {
- anyprop->objtype = pa_policy_object_card;
- method = objdef + 10;
- }
- else if (!strncmp(objdef, "sink-name@", 10)) {
- anyprop->objtype = pa_policy_object_sink;
- method = objdef + 10;
- }
- else if (!strncmp(objdef, "source-name@", 12)) {
- anyprop->objtype = pa_policy_object_source;
- method = objdef + 12;
- }
- else if (!strncmp(objdef, "sink-input-name@", 16)) {
- anyprop->objtype = pa_policy_object_sink_input;
- method = objdef + 16;
- }
- else if (!strncmp(objdef, "source-output-name@", 19)) {
- anyprop->objtype = pa_policy_object_source_output;
- method = objdef + 19;
- }
- else {
- pa_log("invalid object definition in line %d", lineno);
- return -1;
- }
-
- if ((colon = strchr(method, ':')) == NULL) {
- pa_log("invalid object definition in line %d", lineno);
- return -1;
- }
-
- *colon = '\0';
- arg = colon + 1;
-
-
- if (!strcmp(method, "equals"))
- anyprop->method = pa_method_equals;
- else if (!strcmp(method, "startswith"))
- anyprop->method = pa_method_startswith;
- else if (!strcmp(method, "matches"))
- anyprop->method = pa_method_matches;
- else {
- pa_log("invalid method '%s' in line %d", method, lineno);
- return -1;
- }
-
- if (!strncmp(propdef, "property:", 9))
- propnam = propdef + 9;
- else {
- pa_log("invalid property definition '%s' in line %d", propdef, lineno);
- return -1;
- }
-
- anyprop->arg = pa_xstrdup(arg);
- anyprop->propnam = pa_xstrdup(propnam);
-
- return 0;
-}
-
-static int cardname_parse(int lineno, char *namedef, struct carddef *carddef)
-{
- char *colon;
- char *method;
- char *arg;
-
- if ((colon = strchr(namedef, ':')) == NULL) {
- pa_log("invalid definition '%s' in line %d", namedef, lineno);
- return -1;
- }
-
- *colon = '\0';
- method = namedef;
- arg = colon + 1;
-
- if (!strcmp(method, "equals"))
- carddef->method = pa_method_equals;
- else if (!strcmp(method, "startswith"))
- carddef->method = pa_method_startswith;
- else if (!strcmp(method, "matches"))
- carddef->method = pa_method_matches;
- else {
- pa_log("invalid method '%s' in line %d", method, lineno);
- return -1;
- }
-
- carddef->arg = pa_xstrdup(arg);
-
- return 0;
-}
-
-static int flags_parse(int lineno, char *flagdef,
- enum section_type sectn,
- uint32_t *flags_ret)
-{
- char *comma;
- char *flagname;
- uint32_t flags;
- int device, card, stream;
-
- flags = 0;
-
- device = card = stream = FALSE;
-
- switch (sectn) {
- case section_device: device = TRUE; break;
- case section_card: card = TRUE; break;
- case section_stream: stream = TRUE; break;
- default: break;
- }
-
-
- while (*(flagname = flagdef) != '\0') {
- if ((comma = strchr(flagdef, ',')) == NULL)
- flagdef += strlen(flagdef);
- else {
- *comma = '\0';
- flagdef = comma + 1;
- }
-
- if ((device || card) && !strcmp(flagname, "disable_notify"))
- flags |= PA_POLICY_DISABLE_NOTIFY;
- else if (stream && !strcmp(flagname, "mute_if_active"))
- flags |= PA_POLICY_LOCAL_MUTE;
- else if (stream && !strcmp(flagname, "max_volume"))
- flags |= PA_POLICY_LOCAL_VOLMAX;
- else {
- pa_log("invalid flag '%s' in line %d", flagname, lineno);
- return -1;
- }
- }
-
- *flags_ret = flags;
-
- return 0;
-}
-
-static int valid_label(int lineno, char *label)
-{
- int c;
-
- if (!isalpha(*label))
- goto invalid;
-
- while((c = *label++) != '\0') {
- if (!isalpha(c) && isdigit(c) && c != '-' && c != '_')
- goto invalid;
- }
-
- return 1;
-
- invalid:
- pa_log("invalid label '%s' in line %d", label, lineno);
- return 0;
-}
-
-#ifndef HAS_SPLIT_STRV
-static char **pa_split_strv(const char *str, const char *sep)
-{
-#define MAX_ENTRIES 1024
-
- char *ptrs[MAX_ENTRIES];
- char buf[4096];
- char *p, *q;
- int len;
- int i;
- char **ret;
-
- pa_assert(str);
- pa_assert(sep);
-
- strncpy(buf, str, sizeof(buf));
- buf[sizeof(buf)-1] = '\0';
-
- len = strlen(sep);
-
- for (p = buf, i = 0; *p && i < MAX_ENTRIES - 1; p = q) {
- ptrs[i++] = pa_xstrdup(p);
-
- if (!(q = strstr(p, sep)))
- q = p + strlen(p);
- else {
- *q = '\0';
- q += len;
- }
- }
-
- ptrs[i++] = NULL;
-
- len = sizeof(char *) * i;
- ret = pa_xmalloc(len);
-
- memcpy(ret, ptrs, len);
-
- return ret;
-
-#undef MAX_ENTRIES
-}
-#endif
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef fooconfigfilefoo
-#define fooconfigfilefoo
-
-#include "userdata.h"
-
-int pa_policy_parse_config_file(struct userdata *, const char *);
-int pa_policy_parse_files_in_configdir(struct userdata *, const char *);
-
-#endif
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <stdarg.h>
-
-#include <pulsecore/pulsecore-config.h>
-
-#include "context.h"
-#include "module-ext.h"
-#include "card-ext.h"
-#include "sink-ext.h"
-#include "source-ext.h"
-#include "sink-input-ext.h"
-#include "source-output-ext.h"
-
-static struct pa_policy_context_variable
- *add_variable(struct pa_policy_context *, char *);
-static void delete_variable(struct pa_policy_context *,
- struct pa_policy_context_variable *);
-
-static struct pa_policy_context_rule
- *add_rule(struct pa_policy_context_variable *,
- enum pa_classify_method, char*);
-static void delete_rule(struct pa_policy_context_variable *,
- struct pa_policy_context_rule *);
-
-static void append_action(struct pa_policy_context_rule *,
- union pa_policy_context_action *);
-static void delete_action(struct pa_policy_context_rule *,
- union pa_policy_context_action *);
-static int perform_action(struct userdata *, union pa_policy_context_action *,
- char *);
-
-static int match_setup(struct pa_policy_match *, enum pa_classify_method,
- char *, char **);
-static void match_cleanup(struct pa_policy_match *);
-
-static int value_setup(union pa_policy_value *, enum pa_policy_value_type,
- va_list);
-static void value_cleanup(union pa_policy_value *);
-
-static void register_object(struct pa_policy_object *,
- enum pa_policy_object_type,
- const char *, void *, int);
-static void unregister_object(struct pa_policy_object *,
- enum pa_policy_object_type, const char *,
- void *, unsigned long, int);
-static const char *get_object_property(struct pa_policy_object *,const char *);
-static void set_object_property(struct pa_policy_object *,
- const char *, const char *);
-static void delete_object_property(struct pa_policy_object *, const char *);
-static pa_proplist *get_object_proplist(struct pa_policy_object *);
-static int object_assert(struct userdata *, struct pa_policy_object *);
-static const char *object_name(struct pa_policy_object *);
-static void fire_object_property_changed_hook(struct pa_policy_object *object);
-
-static unsigned long object_index(enum pa_policy_object_type, void *);
-static const char *object_type_str(enum pa_policy_object_type);
-
-
-struct pa_policy_context *pa_policy_context_new(struct userdata *u)
-{
- struct pa_policy_context *ctx;
-
- ctx = pa_xmalloc0(sizeof(*ctx));
-
- return ctx;
-}
-
-void pa_policy_context_free(struct pa_policy_context *ctx)
-{
- if (ctx != NULL) {
-
- while (ctx->variables != NULL)
- delete_variable(ctx, ctx->variables);
-
- pa_xfree(ctx);
- }
-}
-
-void pa_policy_context_register(struct userdata *u,
- enum pa_policy_object_type what,
- const char *name, void *ptr)
-{
- struct pa_policy_context_variable *var;
- struct pa_policy_context_rule *rule;
- union pa_policy_context_action *actn;
- struct pa_policy_set_property *setprop;
- struct pa_policy_del_property *delprop;
- struct pa_policy_object *object;
- int lineno;
-
- for (var = u->context->variables; var != NULL; var = var->next) {
- for (rule = var->rules; rule != NULL; rule = rule->next) {
- for (actn = rule->actions; actn != NULL; actn = actn->any.next) {
-
- switch (actn->any.type) {
-
- case pa_policy_set_property:
- setprop = &actn->setprop;
- lineno = setprop->lineno;
- object = &setprop->object;
- break;
-
- case pa_policy_delete_property:
- delprop = &actn->delprop;
- lineno = delprop->lineno;
- object = &delprop->object;
- break;
-
- default:
- continue;
- } /* switch */
-
- register_object(object, what, name, ptr, lineno);
-
- } /* for actn */
- } /* for rule */
- } /* for var */
-}
-
-void pa_policy_context_unregister(struct userdata *u,
- enum pa_policy_object_type type,
- const char *name,
- void *ptr,
- unsigned long index)
-{
- struct pa_policy_context_variable *var;
- struct pa_policy_context_rule *rule;
- union pa_policy_context_action *actn;
- struct pa_policy_set_property *setprop;
- struct pa_policy_del_property *delprop;
- struct pa_policy_object *object;
- int lineno;
-
- for (var = u->context->variables; var != NULL; var = var->next) {
- for (rule = var->rules; rule != NULL; rule = rule->next) {
- for (actn = rule->actions; actn != NULL; actn = actn->any.next) {
-
- switch (actn->any.type) {
-
- case pa_policy_set_property:
- setprop = &actn->setprop;
- lineno = setprop->lineno;
- object = &setprop->object;
- break;
-
- case pa_policy_delete_property:
- delprop = &actn->delprop;
- lineno = delprop->lineno;
- object = &delprop->object;
- break;
-
- default:
- continue;
- } /* switch */
-
- unregister_object(object, type, name, ptr, index, lineno);
-
- } /* for actn */
- } /* for rule */
- } /* for var */
-}
-
-struct pa_policy_context_rule *
-pa_policy_context_add_property_rule(struct userdata *u, char *varname,
- enum pa_classify_method method, char *arg)
-{
- struct pa_policy_context_variable *variable;
- struct pa_policy_context_rule *rule;
-
- variable = add_variable(u->context, varname);
- rule = add_rule(variable, method, arg);
-
- return rule;
-}
-
-void
-pa_policy_context_add_property_action(struct pa_policy_context_rule *rule,
- int lineno,
- enum pa_policy_object_type obj_type,
- enum pa_classify_method obj_classify,
- char *obj_name,
- char *prop_name,
- enum pa_policy_value_type value_type,
- ... /* value_arg */)
-{
- union pa_policy_context_action *action;
- struct pa_policy_set_property *setprop;
- va_list value_arg;
-
- action = pa_xmalloc0(sizeof(*action));
- setprop = &action->setprop;
-
- setprop->type = pa_policy_set_property;
- setprop->lineno = lineno;
-
- setprop->object.type = obj_type;
- match_setup(&setprop->object.match, obj_classify, obj_name, NULL);
-
- setprop->property = pa_xstrdup(prop_name);
-
- va_start(value_arg, value_type);
- value_setup(&setprop->value, value_type, value_arg);
- va_end(value_arg);
-
- append_action(rule, action);
-}
-
-void
-pa_policy_context_delete_property_action(struct pa_policy_context_rule *rule,
- int lineno,
- enum pa_policy_object_type obj_type,
- enum pa_classify_method obj_classify,
- char *obj_name,
- char *prop_name)
-{
- union pa_policy_context_action *action;
- struct pa_policy_del_property *delprop;
-
- action = pa_xmalloc0(sizeof(*action));
- delprop = &action->delprop;
-
- delprop->type = pa_policy_delete_property;
- delprop->lineno = lineno;
-
- delprop->object.type = obj_type;
- match_setup(&delprop->object.match, obj_classify, obj_name, NULL);
-
- delprop->property = pa_xstrdup(prop_name);
-
- append_action(rule, action);
-}
-
-int pa_policy_context_variable_changed(struct userdata *u, char *name,
- char *value)
-{
- struct pa_policy_context_variable *var;
- struct pa_policy_context_rule *rule;
- union pa_policy_context_action *actn;
- int success;
-
- success = TRUE;
-
- for (var = u->context->variables; var != NULL; var = var->next) {
- if (!strcmp(name, var->name)) {
- if (!strcmp(value, var->value))
- pa_log_debug("no value change -> no action");
- else {
- pa_xfree(var->value);
- var->value = pa_xstrdup(value);
-
- for (rule = var->rules; rule != NULL; rule = rule->next) {
- if (rule->match.method(value, &rule->match.arg)) {
- for (actn = rule->actions; actn; actn = actn->any.next)
- {
- if (!perform_action(u, actn, value))
- success = FALSE;
- }
- }
- }
- }
-
- break;
- }
- }
-
- return success;
-}
-
-
-static
-struct pa_policy_context_variable *add_variable(struct pa_policy_context *ctx,
- char *name)
-{
- struct pa_policy_context_variable *var;
- struct pa_policy_context_variable *last;
-
- for (last = (struct pa_policy_context_variable *)&ctx->variables;
- last->next != NULL;
- last = last->next)
- {
- var = last->next;
-
- if (!strcmp(name, var->name))
- return var;
- }
-
- var = pa_xmalloc0(sizeof(*var));
-
- var->name = pa_xstrdup(name);
- var->value = pa_xstrdup("");
-
- last->next = var;
-
- pa_log_debug("created context variable '%s'", var->name);
-
- return var;
-}
-
-static void delete_variable(struct pa_policy_context *ctx,
- struct pa_policy_context_variable *variable)
-{
- struct pa_policy_context_variable *last;
-
- for (last = (struct pa_policy_context_variable *)&ctx->variables;
- last->next != NULL;
- last = last->next)
- {
- if (last->next == variable) {
- last->next = variable->next;
-
-#if 0
- pa_log_debug("delete context variable '%s'", variable->name);
-#endif
-
- pa_xfree(variable->name);
-
- while (variable->rules != NULL)
- delete_rule(variable, variable->rules);
-
- pa_xfree(variable);
-
- return;
- }
- }
-
- pa_log("%s(): confused with data structures: can't find variable",
- __FUNCTION__);
-}
-
-static struct pa_policy_context_rule *
-add_rule(struct pa_policy_context_variable *variable,
- enum pa_classify_method method,
- char *arg)
-{
- struct pa_policy_context_rule *rule = pa_xmalloc0(sizeof(*rule));
- struct pa_policy_context_rule *last;
- char *method_name;
-
- if (!match_setup(&rule->match, method, arg, &method_name)) {
- pa_log("%s: invalid rule definition (method %s)",
- __FUNCTION__, method_name);
- pa_xfree(rule);
- return NULL;
- };
-
-
- for (last = (struct pa_policy_context_rule *)&variable->rules;
- last->next != NULL;
- last = last->next)
- ;
-
- last->next = rule;
-
- return rule;
-}
-
-static void delete_rule(struct pa_policy_context_variable *variable,
- struct pa_policy_context_rule *rule)
-{
- struct pa_policy_context_rule *last;
-
- for (last = (struct pa_policy_context_rule *)&variable->rules;
- last->next != NULL;
- last = last->next)
- {
- if (last->next == rule) {
- last->next = rule->next;
-
- match_cleanup(&rule->match);
-
- while (rule->actions != NULL)
- delete_action(rule, rule->actions);
-
- pa_xfree(rule);
-
- return;
- }
- }
-
- pa_log("%s(): confused with data structures: can't find rule",
- __FUNCTION__);
-}
-
-
-static void append_action(struct pa_policy_context_rule *rule,
- union pa_policy_context_action *action)
-{
- union pa_policy_context_action *last;
-
- for (last = (union pa_policy_context_action *)&rule->actions;
- last->any.next != NULL;
- last = last->any.next)
- ;
-
- last->any.next = action;
-}
-
-static void delete_action(struct pa_policy_context_rule *rule,
- union pa_policy_context_action *action)
-{
- union pa_policy_context_action *last;
- struct pa_policy_set_property *setprop;
-
- for (last = (union pa_policy_context_action *)&rule->actions;
- last->any.next != NULL;
- last = last->any.next)
- {
- if (last->any.next == action) {
- last->any.next = action->any.next;
-
- switch (action->any.type) {
-
- case pa_policy_set_property:
- setprop = &action->setprop;
-
- match_cleanup(&setprop->object.match);
- free(setprop->property);
- value_cleanup(&setprop->value);
-
- break;
-
- default:
- pa_log("%s(): confused with data structure: invalid action "
- "type %d", __FUNCTION__, action->any.type);
- return; /* better to leak than corrupt :) */
- }
-
- free(action);
-
- return;
- }
- }
-
- pa_log("%s(): confused with data structures: can't find action",
- __FUNCTION__);
-}
-
-static int perform_action(struct userdata *u,
- union pa_policy_context_action *action,
- char *var_value)
-{
- struct pa_policy_set_property *setprop;
- struct pa_policy_del_property *delprop;
- struct pa_policy_object *object;
- const char *old_value;
- const char *prop_value;
- const char *objname;
- const char *objtype;
- int success;
-
- switch (action->any.type) {
-
- case pa_policy_set_property:
- setprop = &action->setprop;
- object = &setprop->object;
-
- if (!object_assert(u, object))
- success = FALSE;
- else {
- switch (setprop->value.type) {
-
- case pa_policy_value_constant:
- prop_value = setprop->value.constant.string;
- break;
-
- case pa_policy_value_copy:
- prop_value = var_value;
- break;
-
- default:
- prop_value = NULL;
- break;
- }
-
- if (prop_value == NULL)
- success = FALSE;
- else {
- success = TRUE;
-
- old_value = get_object_property(object, setprop->property);
- objname = object_name(object);
- objtype = object_type_str(object->type);
-
- if (!strcmp(prop_value, old_value)) {
- pa_log_debug("%s '%s' property '%s' value is already '%s'",
- objtype, objname, setprop->property,
- prop_value);
- }
- else {
- pa_log_debug("setting %s '%s' property '%s' to '%s'",
- objtype, objname, setprop->property,
- prop_value);
-
- set_object_property(object, setprop->property, prop_value);
- }
- }
- }
- break;
-
- case pa_policy_delete_property:
- delprop = &action->delprop;
- object = &delprop->object;
-
- if (!object_assert(u, object))
- success = FALSE;
- else {
- success = TRUE;
-
- objname = object_name(object);
- objtype = object_type_str(object->type);
-
- pa_log_debug("deleting %s '%s' property '%s'",
- objtype, objname, delprop->property);
-
- delete_object_property(object, delprop->property);
- }
- break;
-
- default:
- success = FALSE;
- break;
- }
-
- return success;
-}
-
-static int match_setup(struct pa_policy_match *match,
- enum pa_classify_method method,
- char *arg,
- char **method_name_ret)
-{
- char *method_name;
- int success = TRUE;
-
- switch (method) {
-
- case pa_method_equals:
- method_name = "equals";
- match->method = pa_classify_method_equals;
- match->arg.string = pa_xstrdup(arg);
- break;
-
- case pa_method_startswith:
- method_name = "startswidth";
- match->method = pa_classify_method_startswith;
- match->arg.string = pa_xstrdup(arg);
- break;
-
- case pa_method_true:
- method_name = "true";
- match->method = pa_classify_method_true;
- memset(&match->arg, 0, sizeof(match->arg));
- break;
-
- case pa_method_matches:
- method_name = "matches";
- if (regcomp(&match->arg.rexp, arg, 0) == 0) {
- match->method = pa_classify_method_matches;
- break;
- }
- /* intentional fall trough */
-
- default:
- memset(match, 0, sizeof(*match));
- method_name = "<unknown>";
- success = FALSE;
- break;
- };
-
- if (method_name_ret != NULL)
- *method_name_ret = method_name;
-
- return success;
-}
-
-
-static void match_cleanup(struct pa_policy_match *match)
-{
- if (match->method == pa_classify_method_matches)
- regfree(&match->arg.rexp);
- else
- pa_xfree((void *)match->arg.string);
-
- memset(match, 0, sizeof(*match));
-}
-
-static int value_setup(union pa_policy_value *value,
- enum pa_policy_value_type type,
- va_list ap)
-{
- struct pa_policy_value_constant *constant;
- struct pa_policy_value_copy *copy;
- va_list arg;
- char *string;
- int success = TRUE;
-
- va_copy(arg, ap);
-
- switch (type) {
-
- case pa_policy_value_constant:
- constant = &value->constant;
- string = va_arg(arg, char *);
-
- constant->type = pa_policy_value_constant;
- constant->string = pa_xstrdup(string);
-
- break;
-
- case pa_policy_value_copy:
- copy = &value->copy;
-
- copy->type = pa_policy_value_copy;
-
- break;
-
- default:
- memset(value, 0, sizeof(*value));
- success = FALSE;
- break;
- }
-
- va_end(arg);
-
- return success;
-}
-
-static void value_cleanup(union pa_policy_value *value)
-{
- switch (value->type) {
-
- case pa_policy_value_constant:
- pa_xfree(value->constant.string);
- break;
-
- default:
- break;
- }
-}
-
-static void register_object(struct pa_policy_object *object,
- enum pa_policy_object_type type,
- const char *name, void *ptr, int lineno)
-{
- const char *type_str;
-
- if (object->type == type && object->match.method(name,&object->match.arg)){
-
- type_str = object_type_str(type);
-
- if (object->ptr != NULL) {
- pa_log("multiple match for %s '%s' (line %d in config file)",
- type_str, name, lineno);
- }
- else {
- pa_log_debug("registering context-rule for %s '%s' "
- "(line %d in config file)", type_str, name, lineno);
-
- object->ptr = ptr;
- object->index = object_index(type, ptr);
-
- }
- }
-}
-
-static void unregister_object(struct pa_policy_object *object,
- enum pa_policy_object_type type,
- const char *name,
- void *ptr,
- unsigned long index,
- int lineno)
-{
- if (( ptr && ptr == object->ptr ) ||
- (!ptr && type == object->type && index == object->index) ) {
-
- pa_log_debug("unregistering context-rule for %s '%s' "
- "(line %d in config file)",
- object_type_str(object->type), name, lineno);
-
- object->ptr = NULL;
- object->index = PA_IDXSET_INVALID;
- }
-}
-
-
-static const char *get_object_property(struct pa_policy_object *object,
- const char *property)
-{
- pa_proplist *proplist;
- const char *propval;
- const char *value = "<undefined>";
-
- if (object->ptr != NULL) {
-
-
- if ((proplist = get_object_proplist(object)) != NULL) {
- propval = pa_proplist_gets(proplist, property);
-
- if (propval != NULL && propval[0] != '\0')
- value = propval;
- }
- }
-
- return value;
-}
-
-static void set_object_property(struct pa_policy_object *object,
- const char *property, const char *value)
-{
- pa_proplist *proplist;
-
- if (object->ptr != NULL) {
- if ((proplist = get_object_proplist(object)) != NULL) {
- pa_proplist_sets(proplist, property, value);
- fire_object_property_changed_hook(object);
- }
- }
-}
-
-static void delete_object_property(struct pa_policy_object *object,
- const char *property)
-{
- pa_proplist *proplist;
-
- if (object->ptr != NULL) {
- if ((proplist = get_object_proplist(object)) != NULL) {
- pa_proplist_unset(proplist, property);
- fire_object_property_changed_hook(object);
- }
- }
-}
-
-static pa_proplist *get_object_proplist(struct pa_policy_object *object)
-{
- pa_proplist *proplist;
-
- switch (object->type) {
-
- case pa_policy_object_module:
- proplist = ((struct pa_module *)object->ptr)->proplist;
- break;
-
- case pa_policy_object_card:
- proplist = ((struct pa_card *)object->ptr)->proplist;
- break;
-
- case pa_policy_object_sink:
- proplist = ((struct pa_sink *)object->ptr)->proplist;
- break;
-
- case pa_policy_object_source:
- proplist = ((struct pa_source *)object->ptr)->proplist;
- break;
-
- case pa_policy_object_sink_input:
- proplist = ((struct pa_sink_input *)object->ptr)->proplist;
- break;
-
- case pa_policy_object_source_output:
- proplist = ((struct pa_source_output *)object->ptr)->proplist;
- break;
-
- default:
- proplist = NULL;
- break;
- }
-
- return proplist;
-}
-
-
-static int object_assert(struct userdata *u, struct pa_policy_object *object)
-{
- void *ptr;
-
- pa_assert(u);
- pa_assert(u->core);
-
- if (object->ptr != NULL && object->index != PA_IDXSET_INVALID) {
-
- switch (object->type) {
-
- case pa_policy_object_module:
- ptr = pa_idxset_get_by_index(u->core->modules, object->index);
-
- if (ptr != object->ptr)
- break;
-
- return TRUE;
-
- case pa_policy_object_card:
- case pa_policy_object_sink:
- case pa_policy_object_source:
- case pa_policy_object_sink_input:
- case pa_policy_object_source_output:
- return TRUE;
-
- default:
- break;
- }
- }
-
- pa_log("%s() failed", __FUNCTION__);
-
- return FALSE;
-}
-
-static const char *object_name(struct pa_policy_object *object)
-{
- const char *name;
-
- switch (object->type) {
-
- case pa_policy_object_module:
- name = pa_module_ext_get_name((struct pa_module *)object->ptr);
- break;
-
- case pa_policy_object_card:
- name = pa_card_ext_get_name((struct pa_card *)object->ptr);
- break;
-
- case pa_policy_object_sink:
- name = pa_sink_ext_get_name((struct pa_sink *)object->ptr);
- break;
-
- case pa_policy_object_source:
- name = pa_source_ext_get_name((struct pa_source *)object->ptr);
- break;
-
- case pa_policy_object_sink_input:
- name = pa_sink_input_ext_get_name((struct pa_sink_input *)object->ptr);
- break;
-
- case pa_policy_object_source_output:
- name = pa_source_output_ext_get_name(
- (struct pa_source_output *)object->ptr);
- break;
-
- default:
- name = "<unknown>";
- break;
- }
-
- return name;
-}
-
-static void fire_object_property_changed_hook(struct pa_policy_object *object)
-{
- pa_core *core;
- pa_core_hook_t hook;
- struct pa_sink *sink;
- struct pa_source *src;
- struct pa_sink_input *sinp;
- struct pa_source_output *sout;
-
- switch (object->type) {
-
- case pa_policy_object_sink:
- sink = object->ptr;
- core = sink->core;
- hook = PA_CORE_HOOK_SINK_PROPLIST_CHANGED;
- break;
-
- case pa_policy_object_source:
- src = object->ptr;
- core = src->core;
- hook = PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED;
- break;
-
- case pa_policy_object_sink_input:
- sinp = object->ptr;
- core = sinp->core;
- hook = PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED;
- break;
-
- case pa_policy_object_source_output:
- sout = object->ptr;
- core = sout->core;
- hook = PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED;
- break;
-
- default:
- return;
- }
-
- pa_hook_fire(&core->hooks[hook], object->ptr);
-}
-
-static unsigned long object_index(enum pa_policy_object_type type, void *ptr)
-{
- switch (type) {
- case pa_policy_object_module:
- return ((struct pa_module *)ptr)->index;
- case pa_policy_object_card:
- return ((struct pa_card *)ptr)->index;
- case pa_policy_object_sink:
- return ((struct pa_sink *)ptr)->index;
- case pa_policy_object_source:
- return ((struct pa_source *)ptr)->index;
- case pa_policy_object_sink_input:
- return ((struct pa_sink_input *)ptr)->index;
- case pa_policy_object_source_output:
- return ((struct pa_source_output *)ptr)->index;
- default:
- return PA_IDXSET_INVALID;
- }
-}
-
-
-static const char *object_type_str(enum pa_policy_object_type type)
-{
- switch (type) {
- case pa_policy_object_module: return "module";
- case pa_policy_object_card: return "card";
- case pa_policy_object_sink: return "sink";
- case pa_policy_object_source: return "source";
- case pa_policy_object_sink_input: return "sink-input";
- case pa_policy_object_source_output: return "source-output";
- default: return "<unknown>";
- }
-}
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef foopolicycontextfoo
-#define foopolicycontextfoo
-
-#include "classify.h"
-
-enum pa_policy_action_type {
- pa_policy_action_unknown = 0,
- pa_policy_action_min = pa_policy_action_unknown,
-
- pa_policy_set_property,
- pa_policy_delete_property,
-
- pa_policy_action_max
-};
-
-enum pa_policy_object_type {
- pa_policy_object_unknown = 0,
- pa_policy_object_min = pa_policy_object_unknown,
-
- pa_policy_object_module,
- pa_policy_object_card,
- pa_policy_object_sink,
- pa_policy_object_source,
- pa_policy_object_sink_input,
- pa_policy_object_source_output,
-
- pa_policy_object_max
-};
-
-enum pa_policy_value_type {
- pa_policy_value_unknown = 0,
- pa_policy_value_min = pa_policy_value_unknown,
-
- pa_policy_value_constant, /* constant value */
- pa_policy_value_copy, /* copy of the value of context var. */
-
- pa_policy_value_max
-};
-
-struct pa_policy_match {
- int (*method)(const char *,
- union pa_classify_arg *);
- union pa_classify_arg arg;
-};
-
-struct pa_policy_object {
- enum pa_policy_object_type type;
- struct pa_policy_match match;
- void *ptr;
- unsigned long index;
-};
-
-struct pa_policy_value_constant {
- enum pa_policy_value_type type;
- char *string;
-};
-
-struct pa_policy_value_copy {
- enum pa_policy_value_type type;
-};
-
-union pa_policy_value {
- enum pa_policy_value_type type;
- struct pa_policy_value_constant constant;
- struct pa_policy_value_copy copy;
-};
-
-#define PA_POLICY_CONTEXT_ACTION_COMMON \
- union pa_policy_context_action *next; \
- int lineno; \
- enum pa_policy_action_type type
-
-struct pa_policy_context_action_any {
- PA_POLICY_CONTEXT_ACTION_COMMON;
-};
-
-
-struct pa_policy_set_property {
- PA_POLICY_CONTEXT_ACTION_COMMON;
- struct pa_policy_object object;
- char *property;
- union pa_policy_value value;
-};
-
-struct pa_policy_del_property {
- PA_POLICY_CONTEXT_ACTION_COMMON;
- struct pa_policy_object object;
- char *property;
-};
-
-union pa_policy_context_action {
- struct pa_policy_context_action_any any;
- struct pa_policy_set_property setprop;
- struct pa_policy_del_property delprop;
-};
-
-struct pa_policy_context_rule {
- struct pa_policy_context_rule *next;
- struct pa_policy_match match; /* for the variable value */
- union pa_policy_context_action *actions;
-};
-
-struct pa_policy_context_variable {
- struct pa_policy_context_variable *next;
- char *name;
- char *value;
- struct pa_policy_context_rule *rules;
-};
-
-struct pa_policy_context {
- struct pa_policy_context_variable *variables;
-};
-
-
-struct pa_policy_context *pa_policy_context_new(struct userdata *);
-void pa_policy_context_free(struct pa_policy_context *);
-
-void pa_policy_context_register(struct userdata *, enum pa_policy_object_type,
- const char *, void *);
-void pa_policy_context_unregister(struct userdata *,enum pa_policy_object_type,
- const char *, void *, unsigned long);
-
-
-struct pa_policy_context_rule
- *pa_policy_context_add_property_rule(struct userdata *, char *,
- enum pa_classify_method, char *);
-
-void pa_policy_context_add_property_action(struct pa_policy_context_rule *,int,
- enum pa_policy_object_type,
- enum pa_classify_method, char *,
- char *,
- enum pa_policy_value_type, ...);
-
-void pa_policy_context_delete_property_action(struct pa_policy_context_rule *,
- int,
- enum pa_policy_object_type,
- enum pa_classify_method,
- char *, char *);
-
-int pa_policy_context_variable_changed(struct userdata *, char *, char *);
-
-#endif
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
#include "userdata.h"
#include "dbusif.h"
-#include "classify.h"
-#include "context.h"
-#include "policy-group.h"
-#include "sink-ext.h"
-#include "source-ext.h"
-#include "card-ext.h"
#include "audiomgr.h"
#define ADMIN_DBUS_MANAGER "org.freedesktop.DBus"
+++ /dev/null
-#include <stdio.h>
-#include <sys/types.h>
-#include <errno.h>
-
-
-#include <pulsecore/macro.h>
-#include <pulse/xmalloc.h>
-
-#include "index-hash.h"
-
-
-struct pa_index_hash_entry {
- struct pa_index_hash_entry *next;
- uint32_t index;
- void *value;
-};
-
-struct pa_index_hash {
- uint32_t mask;
- struct pa_index_hash_entry **table;
-};
-
-
-struct pa_index_hash *pa_index_hash_init(uint32_t bits)
-{
- struct pa_index_hash *hash;
- uint32_t max;
- size_t size;
-
- if (bits > 16)
- bits = 16;
-
- max = 1UL << bits;
- size = sizeof(struct pa_index_hash_entry *) * max;
-
- hash = pa_xmalloc0(size);
-
- hash->mask = max - 1;
- hash->table = pa_xmalloc0(size);
-
- return hash;
-}
-
-void pa_index_hash_free(struct pa_index_hash *hash)
-{
- pa_xfree(hash->table);
- pa_xfree(hash);
-}
-
-void pa_index_hash_add(struct pa_index_hash *hash, uint32_t index, void *value)
-{
- struct pa_index_hash_entry *entry, *prev;
-
- pa_assert(hash);
- pa_assert(hash->table);
-
- prev = (struct pa_index_hash_entry *)(hash->table + (index & hash->mask));
-
- while ((entry = prev->next) != NULL) {
- if (index == entry->index) {
- entry->value = value;
- return;
- }
-
- prev = entry;
- }
-
- entry = pa_xmalloc0(sizeof(struct pa_index_hash_entry));
-
- entry->index = index;
- entry->value = value;
-
- prev->next = entry;
-}
-
-void *pa_index_hash_remove(struct pa_index_hash *hash, uint32_t index)
-{
- struct pa_index_hash_entry *entry, *prev;
- void *value;
-
- pa_assert(hash);
- pa_assert(hash->table);
-
- prev = (struct pa_index_hash_entry *)(hash->table + (index & hash->mask));
-
- while ((entry = prev->next) != NULL) {
- if (index == entry->index) {
- prev->next = entry->next;
-
- value = entry->value;
- pa_xfree(entry);
-
- return value;
- }
-
- prev = entry;
- }
-
- return NULL;
-}
-
-void *pa_index_hash_lookup(struct pa_index_hash *hash, uint32_t index)
-{
- struct pa_index_hash_entry *entry;
-
- pa_assert(hash);
- pa_assert(hash->table);
-
- for (entry = hash->table[index & hash->mask]; entry; entry = entry->next) {
- if (index == entry->index)
- return entry->value;
- }
-
- return NULL;
-}
-
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef fooindexhashfoo
-#define fooindexhashfoo
-
-#include <stdint.h>
-
-struct pa_index_hash;
-
-struct pa_index_hash *pa_index_hash_init(uint32_t);
-void pa_index_hash_free(struct pa_index_hash *);
-void pa_index_hash_add(struct pa_index_hash *, uint32_t, void *);
-void *pa_index_hash_remove(struct pa_index_hash *, uint32_t);
-void *pa_index_hash_lookup(struct pa_index_hash *, uint32_t);
-
-
-#endif /* fooindexhashfoo */
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulse/def.h>
-#include <pulsecore/module.h>
-
-#include "module-ext.h"
-#include "context.h"
-
-#define HASH_INDEX_BITS 8
-#define HASH_INDEX_GAP 2
-#define HASH_INDEX_MAX (1 << HASH_INDEX_BITS)
-#define HASH_INDEX_MASK (HASH_INDEX_MAX - 1)
-#define HASH_TABLE_SIZE (HASH_INDEX_MAX << HASH_INDEX_GAP)
-#define HASH_TABLE_MASK (HASH_TABLE_SIZE - 1)
-#define HASH_SEARCH_MAX HASH_INDEX_MAX
-
-#define HASH_INDEX(i) (((i) & HASH_INDEX_MASK) << HASH_INDEX_GAP)
-#define HASH_INDEX_NEXT(i) (((i) + 1) & HASH_TABLE_MASK)
-
-
-struct hash_entry {
- unsigned long index;
- struct pa_module *module;
-};
-
-
-struct hash_entry hash_table[HASH_TABLE_SIZE];
-
-
-static void handle_module_events(pa_core *, pa_subscription_event_type_t,
- uint32_t, void *);
-static void handle_new_module(struct userdata *, struct pa_module *);
-static void handle_removed_module(struct userdata *, unsigned long);
-
-static int hash_add(struct pa_module *);
-static int hash_delete(unsigned long);
-
-
-struct pa_module_evsubscr *pa_module_ext_subscription(struct userdata *u)
-{
- struct pa_module_evsubscr *subscr;
-
- pa_assert(u);
- pa_assert(u->core);
-
- subscr = pa_xnew0(struct pa_module_evsubscr, 1);
-
- subscr->ev = pa_subscription_new(u->core, 1<<PA_SUBSCRIPTION_EVENT_MODULE,
- handle_module_events, (void *)u);
-
- return subscr;
-}
-
-void pa_module_ext_subscription_free(struct pa_module_evsubscr *subscr)
-{
- pa_assert(subscr);
-
- pa_subscription_free(subscr->ev);
-}
-
-
-void pa_module_ext_discover(struct userdata *u)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_module *module;
-
- pa_assert(u);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->modules));
-
- while ((module = pa_idxset_iterate(idxset, &state, NULL)) != NULL) {
- hash_add(module);
- handle_new_module(u, module);
- }
-}
-
-char *pa_module_ext_get_name(struct pa_module *module)
-{
- return module->name ? module->name : (char *)"<unknown>";
-}
-
-static void handle_module_events(pa_core *c, pa_subscription_event_type_t t,
- uint32_t idx, void *userdata)
-{
- struct userdata *u = userdata;
- uint32_t et = t & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
- struct pa_module *module;
- char *name;
-
- pa_assert(u);
-
- switch (et) {
-
- case PA_SUBSCRIPTION_EVENT_NEW:
- if ((module = pa_idxset_get_by_index(c->modules, idx)) != NULL) {
- name = pa_module_ext_get_name(module);
-
- if (hash_add(module)) {
- pa_log_debug("new module #%d '%s'", idx, name);
- handle_new_module(u, module);
- }
- }
- break;
-
- case PA_SUBSCRIPTION_EVENT_REMOVE:
- if (hash_delete(idx)) {
- pa_log_debug("remove module #%d", idx);
- handle_removed_module(u, idx);
- }
- break;
-
- default:
- break;
- }
-}
-
-static void handle_new_module(struct userdata *u, struct pa_module *module)
-{
- char *name;
-
- if (module && u) {
- name = pa_module_ext_get_name(module);
-
- pa_policy_context_register(u, pa_policy_object_module, name, module);
- }
-}
-
-static void handle_removed_module(struct userdata *u, unsigned long idx)
-{
- char name[256];
-
- if (u) {
-
- snprintf(name, sizeof(name), "module #%lu", idx);
-
- pa_policy_context_unregister(u, pa_policy_object_module,
- name, NULL, idx);
- }
-}
-
-
-static int hash_add(struct pa_module *module)
-{
- int hidx = HASH_INDEX(module->index);
- int i;
-
-
- for (i = 0; i < HASH_SEARCH_MAX; i++) {
-
- if (hash_table[hidx].module == NULL) {
- hash_table[hidx].index = module->index;
- hash_table[hidx].module = module;
- return TRUE;
- }
-
- if (hash_table[hidx].module == module)
- break;
- }
-
- return FALSE;
-}
-
-static int hash_delete(unsigned long index)
-{
- int hidx = HASH_INDEX(index);
- int i;
-
-
- for (i = 0; i < HASH_SEARCH_MAX; i++) {
- if (hash_table[hidx].index == index) {
- hash_table[hidx].index = 0;
- hash_table[hidx].module = NULL;
- return TRUE;
- }
-
- hidx = HASH_INDEX_NEXT(hidx);
- }
-
- return FALSE;
-}
-
-
-#ifndef HAS_MODULE_UPDATE_PROPLIST
-void pa_module_update_proplist(pa_module *m,
- pa_update_mode_t mode,
- pa_proplist *p)
-{
- pa_assert(m);
-
- if (p)
- pa_proplist_update(m->proplist, mode, p);
-
- pa_subscription_post(
- m->core,
- PA_SUBSCRIPTION_EVENT_MODULE | PA_SUBSCRIPTION_EVENT_CHANGE,
- m->index
- );
-}
-#endif
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef foomoduleextfoo
-#define foomoduleextfoo
-
-#include "userdata.h"
-
-struct pa_module;
-struct pa_subscription;
-typedef enum pa_update_mode pa_update_mode_t;
-typedef struct pa_proplist pa_proplist;
-
-struct pa_module_evsubscr {
- struct pa_subscription *ev;
-};
-
-
-struct pa_module_evsubscr *pa_module_ext_subscription(struct userdata *);
-void pa_module_ext_subscription_free(struct pa_module_evsubscr *);
-void pa_module_ext_discover(struct userdata *);
-char *pa_module_ext_get_name(struct pa_module *);
-
-#ifndef HAS_MODULE_UPDATE_PROPLIST
-void pa_module_update_proplist(pa_module *, pa_update_mode_t, pa_proplist *);
-#endif
-
-#endif /* foomoduleextfoo */
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulsecore/namereg.h>
-#include <pulse/volume.h>
-
-#include "policy-group.h"
-#include "sink-ext.h"
-#include "source-ext.h"
-#include "sink-input-ext.h"
-#include "source-output-ext.h"
-#include "classify.h"
-#include "dbusif.h"
-
-#define MUTE 1
-#define UNMUTE 0
-
-
-struct target {
- enum pa_policy_route_class class;
- union {
- void *any;
- struct pa_sink *sink;
- struct pa_source *source;
- };
- char *mode;
- char *hwid;
-};
-
-
-struct cursor {
- int idx;
- struct pa_policy_group *grp;
-};
-
-
-static struct pa_sink *defsink;
-static struct pa_source *defsource;
-static uint32_t defsinkidx = PA_IDXSET_INVALID;
-static uint32_t defsrcidx = PA_IDXSET_INVALID;
-static pa_volume_t dbtbl[300];
-
-static int move_group(struct pa_policy_group *, struct target *);
-static int volset_group(struct userdata *, struct pa_policy_group *,
- pa_volume_t);
-static int mute_group_by_route(struct pa_policy_group *,
- int, struct pa_null_sink *);
-static int mute_group_locally(struct userdata *, struct pa_policy_group *,int);
-static int cork_group(struct pa_policy_group *, int);
-
-static struct pa_policy_group *find_group_by_name(struct pa_policy_groupset *,
- char *, uint32_t *);
-
-static struct pa_sink *find_sink_by_type(struct userdata *, char *);
-static struct pa_source *find_source_by_type(struct userdata *, char *);
-
-static uint32_t hash_value(char *);
-
-static pa_volume_t dB_to_sw_volume(int);
-
-
-struct pa_policy_groupset *pa_policy_groupset_new(struct userdata *u)
-{
- static int initialized;
-
- double dB;
- struct pa_policy_groupset *gset;
- int i;
-
- pa_assert(u);
-
- if (!initialized) {
- initialized = TRUE;
-
- for (i = 0; i < (sizeof(dbtbl) / sizeof(dbtbl[0])); i++) {
- dB = -(double)i;
- dbtbl[i] = pa_sw_volume_from_dB(dB);
- }
- }
-
- gset = pa_xnew0(struct pa_policy_groupset, 1);
-
- return gset;
-}
-
-void pa_policy_groupset_free(struct pa_policy_groupset *gset)
-{
- pa_assert(gset);
-
- pa_xfree(gset);
-}
-
-void pa_policy_groupset_update_default_sink(struct userdata *u, uint32_t idx)
-{
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group;
- char *defsinkname;
- int i;
-
- pa_assert(u);
- pa_assert_se((gset = u->groups));
-
- /*
- * Remove the sink from all groups if idx were specified
- * and equals to the default sink's index
- */
-
- if (defsink != NULL && defsinkidx == idx) {
- pa_log_debug("Unset default sink (idx=%d)", idx);
-
- for (i = 0; i < PA_POLICY_GROUP_HASH_DIM; i++) {
- for (group = gset->hash_tbl[i]; group; group = group->next) {
- if (group->sinkidx == defsinkidx) {
- pa_log_debug(" unset default sink for group '%s'",
- group->name);
- group->sink = NULL;
- group->sinkidx = PA_IDXSET_INVALID;
- }
- }
- }
-
- defsink = NULL;
- defsinkidx = PA_IDXSET_INVALID;
- }
-
- /*
- * Try to find the default sink if we do not had any
- */
-
- if (defsink == NULL) {
- defsink = pa_namereg_get(u->core, NULL, PA_NAMEREG_SINK);
-
- if (defsink != NULL) {
- defsinkname = pa_sink_ext_get_name(defsink);
- defsinkidx = defsink->index;
-
- pa_log_debug("Set default sink to '%s' (idx=%d)",
- defsinkname, defsinkidx);
-
- for (i = 0; i < PA_POLICY_GROUP_HASH_DIM; i++) {
- for (group = gset->hash_tbl[i]; group; group = group->next) {
- if (group->sinkname == NULL && group->sink == NULL) {
- pa_log_debug(" set sink '%s' as default for "
- "group '%s'", defsinkname, group->name);
- group->sink = defsink;
- group->sinkidx = defsinkidx;
-
- /* TODO: we should move the streams to defsink */
- }
- }
- }
- }
- }
-}
-
-
-void pa_policy_groupset_register_sink(struct userdata *u, struct pa_sink *sink)
-{
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group;
- char *sinkname;
- uint32_t sinkidx;
- int i;
-
- pa_assert(u);
- pa_assert(sink);
- pa_assert_se((gset = u->groups));
-
- sinkname = pa_sink_ext_get_name(sink);
- sinkidx = sink->index;
-
- if (sinkname && sinkname[0]) {
- pa_log_debug("Register sink '%s' (idx=%d)", sinkname, sinkidx);
-
- for (i = 0; i < PA_POLICY_GROUP_HASH_DIM; i++) {
- for (group = gset->hash_tbl[i]; group; group = group->next) {
- if (group->sinkname && !strcmp(group->sinkname, sinkname)) {
- pa_log_debug(" set sink '%s' as default for group '%s'",
- sinkname, group->name);
-
- group->sink = sink;
- group->sinkidx = sinkidx;
-
- /* TODO: we should move the streams to the sink */
- }
- }
- }
- }
-}
-
-void pa_policy_groupset_unregister_sink(struct userdata *u, uint32_t sinkidx)
-{
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group;
- int i;
-
- pa_assert(u);
- pa_assert_se((gset = u->groups));
-
- pa_log_debug("Unregister sink (idx=%d)", sinkidx);
-
- for (i = 0; i < PA_POLICY_GROUP_HASH_DIM; i++) {
- for (group = gset->hash_tbl[i]; group; group = group->next) {
- if (group->sinkidx == sinkidx) {
- pa_log_debug(" unset default sink for group '%s'",
- group->name);
-
- group->sink = NULL;
- group->sinkidx = PA_IDXSET_INVALID;
-
- /* TODO: we should move the streams to somewhere */
- }
- }
- }
-}
-
-void pa_policy_groupset_register_source(struct userdata *u,
- struct pa_source *source)
-{
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group;
- char *srcname;
- uint32_t srcidx;
- int i;
-
- pa_assert(u);
- pa_assert(source);
- pa_assert_se((gset = u->groups));
-
- srcname = pa_source_ext_get_name(source);
- srcidx = source->index;
-
- if (srcname && srcname[0]) {
- pa_log_debug("Register source '%s' (idx=%d)", srcname, srcidx);
-
- for (i = 0; i < PA_POLICY_GROUP_HASH_DIM; i++) {
- for (group = gset->hash_tbl[i]; group; group = group->next) {
- if (group->srcname && !strcmp(group->srcname, srcname)) {
- pa_log_debug(" set source '%s' as default for group '%s'",
- srcname, group->name);
-
- group->source = source;
- group->srcidx = srcidx;
-
- /* TODO: we should move the streams to the source */
- }
- }
- }
- }
-}
-
-void pa_policy_groupset_unregister_source(struct userdata *u, uint32_t srcidx)
-{
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group;
- int i;
-
- pa_assert(u);
- pa_assert_se((gset = u->groups));
-
- pa_log_debug("Unregister source (idx=%d)", srcidx);
-
- for (i = 0; i < PA_POLICY_GROUP_HASH_DIM; i++) {
- for (group = gset->hash_tbl[i]; group; group = group->next) {
- if (group->srcidx == srcidx) {
- pa_log_debug(" unset default source for group '%s'",
- group->name);
-
- group->source = NULL;
- group->srcidx = PA_IDXSET_INVALID;
-
- /* TODO: we should move the streams to the somwhere */
- }
- }
- }
-}
-
-void pa_policy_groupset_create_default_group(struct userdata *u,
- const char *preempt)
-{
- static char *name = (char *)PA_POLICY_DEFAULT_GROUP_NAME;
- static uint32_t flags = PA_POLICY_GROUP_FLAGS_CLIENT;
-
- struct pa_policy_groupset *gset;
-
- pa_assert(u);
- pa_assert_se((gset = u->groups));
-
- if (preempt != NULL) {
- if (!strcmp(preempt, "on")) {
- flags |= PA_POLICY_GROUP_FLAG_MEDIA_NOTIFY;
- }
- else if (strcmp(preempt, "off")) {
- pa_log("invalid value '%s' for preemption", preempt);
- }
- }
-
- pa_log_info("group '%s' preemption is %s", name,
- (flags & PA_POLICY_GROUP_FLAG_MEDIA_NOTIFY) ? "on" : "off");
-
-
- gset->dflt = pa_policy_group_new(u, name, NULL, NULL, flags);
-}
-
-int pa_policy_groupset_restore_volume(struct userdata *u, struct pa_sink *sink)
-{
- struct pa_policy_group *group;
- void *cursor = NULL;
- int ret = 0;
-
- if (sink) {
- while ((group = pa_policy_group_scan(u->groups, &cursor)) != NULL) {
- if (sink == group->sink) {
- if (mute_group_locally(u, group, UNMUTE) < 0)
- ret = -1;
- }
- }
- }
-
- return ret;
-}
-
-
-struct pa_policy_group *pa_policy_group_new(struct userdata *u, char *name,
- char *sinkname, char *srcname,
- uint32_t flags)
-{
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group;
- uint32_t idx;
-
- pa_assert(u);
- pa_assert_se((gset = u->groups));
-
- if ((group = find_group_by_name(gset, name, &idx)) != NULL)
- return group;
-
- group = pa_xnew0(struct pa_policy_group, 1);
-
- group->next = gset->hash_tbl[idx];
- group->flags = flags;
- group->name = pa_xstrdup(name);
- group->limit = PA_VOLUME_NORM;
- group->sinkname = sinkname ? pa_xstrdup(sinkname) : NULL;
- group->sink = sinkname ? NULL : defsink;
- group->sinkidx = sinkname ? PA_IDXSET_INVALID : defsinkidx;
- group->srcname = srcname ? pa_xstrdup(srcname) : NULL;
- group->source = srcname ? NULL : defsource;
- group->srcidx = srcname ? PA_IDXSET_INVALID : defsrcidx;
-
- gset->hash_tbl[idx] = group;
-
- pa_log_info("created group (%s|%d|%s|0x%04x)", group->name,
- (group->limit * 100) / PA_VOLUME_NORM,
- group->sink?group->sink->name:"<null>",
- group->flags);
-
- return group;
-}
-
-void pa_policy_group_free(struct pa_policy_groupset *gset, char *name)
-{
- struct pa_policy_group *group;
- struct pa_policy_group *dflt;
- struct pa_policy_group *prev;
- struct pa_sink_input *sinp;
- struct pa_sink_input_list *sil;
- struct pa_sink_input_list *nxtsi;
- struct pa_source_output *sout;
- struct pa_source_output_list *sol;
- struct pa_source_output_list *nxtso;
- char *dnam;
- uint32_t idx;
-
- pa_assert(gset);
- pa_assert(name);
-
- if ((group = find_group_by_name(gset, name, &idx)) != NULL) {
- for (prev = (struct pa_policy_group *)&gset->hash_tbl[idx];
- prev->next != NULL;
- prev = prev->next)
- {
- if (group == prev->next) {
- if (group->sinpls != NULL) {
- dflt = gset->dflt;
-
- if (group == dflt) {
- /*
- * If the default group is going to be deleted,
- * release all sink-inputs
- */
- for (sil = group->sinpls; sil; sil = nxtsi) {
- nxtsi = sil->next;
- sinp = sil->sink_input;
-
- pa_sink_input_ext_set_policy_group(sinp, NULL);
-
- pa_xfree(sil);
- }
- }
- else {
- /*
- * Otherwise add the sink-inputs to the default group
- */
- dnam = dflt->name;
-
- for (sil = group->sinpls; sil; sil = sil->next) {
- sinp = sil->sink_input;
-
- pa_sink_input_ext_set_policy_group(sinp, dnam);
-
- if (sil->next == NULL)
- sil->next = dflt->sinpls;
- }
-
- dflt->sinpls = group->sinpls;
- }
- } /* if group->sinpls != NULL */
-
- if (group->soutls != NULL) {
- for (sol = group->soutls; sol; sol = nxtso) {
- nxtso = sol->next;
- sout = sol->source_output;
-
- pa_source_output_ext_set_policy_group(sout, NULL);
-
- pa_xfree(sol);
- }
- } /* if group->soutls */
-
- pa_xfree(group->name);
- pa_xfree(group->sinkname);
- pa_xfree(group->portname);
- pa_xfree(group->srcname);
-
- prev->next = group->next;
-
- pa_xfree(group);
-
- break;
- }
- } /* for */
- } /* if find_group */
-}
-
-struct pa_policy_group *pa_policy_group_find(struct userdata *u, char *name)
-{
- struct pa_policy_groupset *gset;
-
- assert(u);
- assert((gset = u->groups));
- assert(name);
-
- return find_group_by_name(gset, name, NULL);
-}
-
-void pa_policy_group_insert_sink_input(struct userdata *u,
- char *name,
- struct pa_sink_input *si,
- uint32_t flags)
-{
- static const char *media = "audio_playback";
- static uint32_t route_flags = PA_POLICY_GROUP_FLAG_SET_SINK |
- PA_POLICY_GROUP_FLAG_ROUTE_AUDIO;
- static uint32_t setsink_flag = PA_POLICY_GROUP_FLAG_SET_SINK;
-
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group, *g;
- struct pa_sink_input_list *sl;
- struct pa_null_sink *ns;
- char *sinp_name;
- char *sink_name;
- int local_route;
- int local_mute;
- int static_route;
- void *cursor = NULL;
-
-
- pa_assert(u);
- pa_assert_se((gset = u->groups));
- pa_assert(si);
-
- if (name == NULL)
- group = gset->dflt;
- else
- group = find_group_by_name(gset, name, NULL);
-
- if (group != NULL) {
- pa_sink_input_ext_set_policy_group(si, group->name);
-
- sl = pa_xnew0(struct pa_sink_input_list, 1);
- sl->next = group->sinpls;
- sl->index = si->index;
- sl->sink_input = si;
-
- group->sinpls = sl;
-
- if (group->sink != NULL) {
- sinp_name = pa_sink_input_ext_get_name(si);
- sink_name = pa_sink_ext_get_name(group->sink);
-
- local_route = flags & PA_POLICY_LOCAL_ROUTE;
- local_mute = flags & PA_POLICY_LOCAL_MUTE;
-
- if (group->mutebyrt & !local_route) {
- ns = u->nullsink;
-
- pa_log_debug("move sink input '%s' to sink '%s'",
- sinp_name, ns->name);
-
- pa_sink_input_move_to(si, ns->sink, TRUE);
- }
- else if (group->flags & route_flags) {
- static_route = ((group->flags & route_flags) == setsink_flag);
-
- pa_log_debug("move stream '%s'/'%s' to sink '%s'",
- group->name, sinp_name, sink_name);
-
- pa_sink_input_move_to(si, group->sink, TRUE);
-
- if (local_route && group->portname && static_route) {
- pa_sink_ext_override_port(u, group->sink, group->portname);
- }
- }
-
-
- if (group->flags & PA_POLICY_GROUP_FLAG_CORK_STREAM) {
- if (group->corked) {
- pa_log_debug("stream '%s'/'%s' %scorked",
- group->name, sinp_name,
- group->corked ? "" : "un");
-
- pa_sink_input_cork(si, group->corked);
- }
- }
-
-
- if (local_mute) {
- while ((g = pa_policy_group_scan(u->groups, &cursor)) != NULL){
- if (g->sink && g->sink == group->sink) {
- mute_group_locally(u, g, MUTE);
- }
- }
- }
- else if (group->flags & PA_POLICY_GROUP_FLAG_LIMIT_VOLUME) {
- pa_log_debug("set volume limit %d for sink input '%s'",
- (group->limit * 100) / PA_VOLUME_NORM,sinp_name);
-
- pa_sink_input_ext_set_volume_limit(si, group->limit);
- }
- }
-
- group->sinpcnt++;
-
- if ((group->flags & PA_POLICY_GROUP_FLAG_MEDIA_NOTIFY) &&
- group->sinpcnt == 1)
- {
- pa_log_debug("media notification: group '%s' media '%s' "
- "state 'active'", group->name, media);
-
- pa_policy_dbusif_send_media_status(u, media, group->name, 1);
- }
-
- pa_log_debug("sink input '%s' added to group '%s'",
- pa_sink_input_ext_get_name(si), group->name);
- }
-}
-
-
-void pa_policy_group_remove_sink_input(struct userdata *u, uint32_t idx)
-{
- static const char *media = "audio_playback";
-
- struct pa_policy_group *group;
- struct pa_sink_input_list *prev;
- struct pa_sink_input_list *sl;
- void *cursor = NULL;
-
- pa_assert(u);
- pa_assert(u->groups);
-
- while ((group = pa_policy_group_scan(u->groups, &cursor)) != NULL) {
- for (prev = (struct pa_sink_input_list *)&group->sinpls;
- prev != NULL;
- prev = prev->next)
- {
- if ((sl = prev->next) != NULL && idx == sl->index) {
-
- group->sinpcnt--;
-
- if ((group->flags & PA_POLICY_GROUP_FLAG_MEDIA_NOTIFY) &&
- group->sinpcnt < 1)
- {
- group->sinpcnt = 0;
-
- pa_log_debug("media notification: group '%s' media '%s' "
- "state 'inactive'", group->name, media);
-
- pa_policy_dbusif_send_media_status(u, media,group->name,0);
- }
-
- prev->next = sl->next;
-
- pa_xfree(sl);
-
- pa_log_debug("sink input (idx=%d) removed from group '%s'",
- idx, group->name);
-
- return;
- }
- }
- }
-
- pa_log("Can't remove sink input (idx=%d): not a member of any group", idx);
-}
-
-void pa_policy_group_insert_source_output(struct userdata *u,
- char *name,
- struct pa_source_output *so)
-{
- static const char *media = "audio_recording";
-#if 0
- static uint32_t route_flags = PA_POLICY_GROUP_FLAG_SET_SOURCE |
- PA_POLICY_GROUP_FLAG_ROUTE_AUDIO;
-#endif
-
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group;
- struct pa_source_output_list *sl;
- char *sout_name;
- char *src_name;
-
-
- pa_assert(u);
- pa_assert_se((gset = u->groups));
- pa_assert(so);
-
- if (name == NULL)
- group = gset->dflt;
- else
- group = find_group_by_name(gset, name, NULL);
-
- if (group != NULL) {
- pa_source_output_ext_set_policy_group(so, group->name);
-
- sl = pa_xnew0(struct pa_source_output_list, 1);
- sl->next = group->soutls;
- sl->index = so->index;
- sl->source_output = so;
-
- group->soutls = sl;
-
- if (group->source != NULL) {
- sout_name = pa_source_output_ext_get_name(so);
- src_name = pa_source_ext_get_name(group->source);
-
- if (group->flags & PA_POLICY_GROUP_FLAG_ROUTE_AUDIO) {
- pa_log_debug("move source output '%s' to source '%s'",
- sout_name, src_name);
-
- pa_source_output_move_to(so, group->source, TRUE);
- }
- }
-
- group->soutcnt++;
-
- if ((group->flags & PA_POLICY_GROUP_FLAG_MEDIA_NOTIFY) &&
- group->soutcnt == 1)
- {
- pa_log_debug("media notification: group '%s' media '%s' "
- "state 'active'", group->name, media);
-
- pa_policy_dbusif_send_media_status(u, media, group->name, 1);
- }
-
- pa_log_debug("source output '%s' added to group '%s'",
- pa_source_output_ext_get_name(so), group->name);
- }
-}
-
-
-void pa_policy_group_remove_source_output(struct userdata *u, uint32_t idx)
-{
- static const char *media = "audio_recording";
-
- struct pa_policy_group *group;
- struct pa_source_output_list *prev;
- struct pa_source_output_list *sl;
- void *cursor = NULL;
-
- pa_assert(u);
- pa_assert(u->groups);
-
- while ((group = pa_policy_group_scan(u->groups, &cursor)) != NULL) {
- for (prev = (struct pa_source_output_list *)&group->soutls;
- prev != NULL;
- prev = prev->next)
- {
- if ((sl = prev->next) != NULL && idx == sl->index) {
- group->soutcnt--;
-
- if ((group->flags & PA_POLICY_GROUP_FLAG_MEDIA_NOTIFY) &&
- group->soutcnt < 1)
- {
- group->soutcnt = 0;
-
- pa_log_debug("media notification: group '%s' media '%s' "
- "state 'inactive'", group->name, media);
-
- pa_policy_dbusif_send_media_status(u, media,group->name,0);
- }
-
- prev->next = sl->next;
-
- pa_xfree(sl);
-
- pa_log_debug("source output (idx=%d) removed from group '%s'",
- idx, group->name);
-
- return;
- }
- }
- }
-
- pa_log("Can't remove source output (idx=%d): "
- "not a member of any group", idx);
-}
-
-int pa_policy_group_move_to(struct userdata *u, char *name,
- enum pa_policy_route_class class, char *type,
- char *mode, char *hwid)
-{
- struct pa_policy_group *grp;
- struct target target;
- void *curs;
- int target_is_sink;
- int ret = -1;
-
- pa_assert(u);
-
- target.class = class;
- target.mode = mode ? mode : "";
- target.hwid = hwid ? hwid : "";
-
- switch (class) {
-
- case pa_policy_route_to_sink:
- target.sink = find_sink_by_type(u, type);
- target_is_sink = TRUE;
- break;
-
- case pa_policy_route_to_source:
- target.source = find_source_by_type(u, type);
- target_is_sink = FALSE;
- break;
-
- default:
- target.any = NULL;
- break;
- }
-
-
- if (target.any != NULL) {
- if (name) { /* move the specified group only */
- if ((grp = find_group_by_name(u->groups, name, NULL)) != NULL) {
- if (!(grp->flags & PA_POLICY_GROUP_FLAG_ROUTE_AUDIO))
- ret = 0;
- else
- ret = move_group(grp, &target);
- }
- }
- else { /* move all groups */
- ret = 0;
-
- for (curs = NULL; (grp = pa_policy_group_scan(u->groups, &curs));){
- if ((grp->flags & PA_POLICY_GROUP_FLAG_ROUTE_AUDIO)) {
- if (move_group(grp, &target) < 0)
- ret = -1;
- }
- }
- }
- }
-
- return ret;
-}
-
-int pa_policy_group_cork(struct userdata *u, char *name, int corked)
-{
- struct pa_policy_group *grp;
- int ret;
-
- pa_assert(u);
-
- if ((grp = find_group_by_name(u->groups, name, NULL)) == NULL)
- ret = -1;
- else {
- if (!(grp->flags & PA_POLICY_GROUP_FLAG_CORK_STREAM))
- ret = 0;
- else
- ret = cork_group(grp, corked);
- }
-
- return ret;
-}
-
-
-int pa_policy_group_volume_limit(struct userdata *u, char *name,
- uint32_t percent)
-{
- struct pa_policy_groupset *gset;
- struct pa_policy_group *group;
- struct pa_null_sink *ns;
- int mute;
- int ret;
-
- pa_assert(u);
- pa_assert_se((gset = u->groups));
-
- if (name == NULL)
- group = gset->dflt;
- else
- group = find_group_by_name(gset, name, NULL);
-
- if (group == NULL) {
- pa_log("%s: can't set volume limit: don't know group '%s'",
- __FILE__, name ? name : PA_POLICY_DEFAULT_GROUP_NAME);
- ret = -1;
- }
- else {
- ns = u->nullsink;
-
- if (!(group->flags & PA_POLICY_GROUP_FLAG_LIMIT_VOLUME))
- ret = 0;
- else {
- if (!(group->flags & PA_POLICY_GROUP_FLAG_MUTE_BY_ROUTE))
- ret = volset_group(u, group, percent);
- else {
- if (ns->sink == NULL)
- ret = volset_group(u, group, percent);
- else {
- mute = percent > 0 ? FALSE : TRUE;
- ret = mute_group_by_route(group, mute, ns);
-
- if (!mute)
- volset_group(u, group, percent);
- }
- }
- }
- }
-
- return ret;
-}
-
-
-struct pa_policy_group *pa_policy_group_scan(struct pa_policy_groupset *gset,
- void **pcursor)
-{
- struct cursor *cursor;
- struct pa_policy_group *grp;
-
- pa_assert(gset);
- pa_assert(pcursor);
-
- if ((cursor = *pcursor) == NULL) {
- cursor = pa_xnew0(struct cursor, 1);
- *pcursor = cursor;
- }
-
-
- for (;;) {
- if ((grp = cursor->grp) != NULL) {
- cursor->grp = grp->next;
- return grp;
- }
-
- if (cursor->idx >= PA_POLICY_GROUP_HASH_DIM) {
- pa_xfree(cursor);
- *pcursor = NULL;
- return NULL;
- }
-
- while (cursor->idx < PA_POLICY_GROUP_HASH_DIM &&
- (cursor->grp = gset->hash_tbl[cursor->idx++]) == NULL)
- ;
- }
-}
-
-
-static int move_group(struct pa_policy_group *group, struct target *target)
-{
- static pa_subscription_event_type_t sinkev = PA_SUBSCRIPTION_EVENT_SINK |
- PA_SUBSCRIPTION_EVENT_CHANGE;
- struct pa_core *core;
- struct pa_sink *sink;
- struct pa_source *source;
- struct pa_sink_input_list *sil;
- struct pa_source_output_list *sol;
- struct pa_sink_input *sinp;
- struct pa_source_output *sout;
- pa_proplist *pl;
- const char *old_mode;
- const char *old_hwid;
- int prop_changed;
- char *sinkname;
- int ret = 0;
-
- if (group == NULL || target->any == NULL)
- ret = -1;
- else {
-
- switch (target->class) {
-
- case pa_policy_route_to_sink:
- sink = target->sink;
- core = sink->core;
- pl = sink->proplist;
-
- /* update sink properties if needed */
- old_mode = pa_proplist_gets(pl, PA_PROP_MAEMO_AUDIO_MODE);
- old_hwid = pa_proplist_gets(pl, PA_PROP_MAEMO_ACCESSORY_HWID);
-
- if (old_mode && !strcmp(target->mode, old_mode) &&
- old_hwid && !strcmp(target->hwid, old_hwid) )
- prop_changed = FALSE;
- else {
- prop_changed = TRUE;
-
- pa_proplist_sets(pl,PA_PROP_MAEMO_AUDIO_MODE ,target->mode);
- pa_proplist_sets(pl,PA_PROP_MAEMO_ACCESSORY_HWID,target->hwid);
- }
-
-
- /* move sink inputs to the sink */
- sinkname = pa_sink_ext_get_name(sink);
-
- if (sink == group->sink) {
- if (!group->mutebyrt) {
- pa_log_debug("group '%s' is aready routed to sink '%s'",
- group->name, sinkname);
- }
- }
- else {
- pa_xfree(group->sinkname);
- group->sinkname = pa_xstrdup(sinkname);
- group->sink = sink;
- group->sinkidx = sink->index;
-
- if (!group->mutebyrt) {
- for (sil = group->sinpls; sil; sil = sil->next) {
- sinp = sil->sink_input;
-
- pa_log_debug("move sink input '%s' to sink '%s'",
- pa_sink_input_ext_get_name(sinp),
- sinkname);
-
- if (pa_sink_input_move_to(sinp, sink, TRUE) < 0) {
- ret = -1;
- }
- }
- }
- }
-
- /* in case the sink properties changed announce it */
- if (prop_changed) {
- pa_subscription_post(sink->core, sinkev, sink->index);
- pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED],
- sink);
- }
- break;
-
- case pa_policy_route_to_source:
- source = target->source;
- core = source->core;
- pl = source->proplist;
-
- /* move source outputs to the source */
- if ((source = target->source) == group->source) {
- pa_log_debug("group '%s' is aready routed to source '%s'",
- group->name, pa_source_ext_get_name(source));
- }
- else {
- group->source = source;
-
- for (sol = group->soutls; sol; sol = sol->next) {
- sout = sol->source_output;
-
- pa_log_debug("move source output '%s' to source '%s'",
- pa_source_output_ext_get_name(sout),
- pa_source_ext_get_name(source));
-
- if (pa_source_output_move_to(sout, source, TRUE) < 0) {
- ret = -1;
-
- pa_log("failed to move source output '%s' to source "
- "'%s'", pa_source_output_ext_get_name(sout),
- pa_source_ext_get_name(source));
- }
- }
- }
- break;
-
- default:
- ret = -1;
- break;
- } /* switch class */
- }
-
- return ret;
-}
-
-
-static int volset_group(struct userdata *u,
- struct pa_policy_group *group,
- pa_volume_t percent)
-{
- pa_volume_t limit;
- struct pa_sink_input_list *sl;
- struct pa_sink_input *sinp;
- struct pa_sink *sink;
- struct pa_sink_ext *ext;
- int vset;
- int flat;
- int retval;
-
- limit = ((percent > 100 ? 100 : percent) * PA_VOLUME_NORM) / 100;
- retval = 0;
-
- if (limit == group->limit) {
- pa_log_debug("group '%s' volume limit is already %d",
- group->name, percent);
- }
- else {
- group->limit = limit;
-
- if (!group->locmute) {
- for (sl = group->sinpls; sl != NULL; sl = sl->next) {
- sinp = sl->sink_input;
- vset = pa_sink_input_ext_set_volume_limit(sinp, limit);
-
- if (vset < 0)
- retval = -1;
- else {
- sink = sinp->sink;
- ext = pa_sink_ext_lookup(u, sink);
-
- pa_assert(ext);
-
- pa_log_debug("set volume limit %d for sink input '%s'",
- percent, pa_sink_input_ext_get_name(sinp));
-
- ext->need_volume_setting |= vset;
- }
- }
- }
- }
-
- return 0;
-}
-
-
-static int mute_group_by_route(struct pa_policy_group *group,
- int mute,
- struct pa_null_sink *ns)
-{
- struct pa_sink_input_list *sl;
- struct pa_sink_input *sinp;
- struct pa_sink *sink;
- char *sink_name;
- int ret = 0;
-
- sink = mute ? ns->sink : group->sink;
-
- if (sink == NULL) {
- pa_log("invalid (<null>) target sink for mute-by-route");
- ret = -1;
- }
- else {
- sink_name = pa_sink_ext_get_name(sink);
-
- if ((mute && group->mutebyrt) || (!mute && !group->mutebyrt)) {
- pa_log_debug("group '%s' is already routed to '%s' by "
- "mute-by-route (mute is %s)", group->name, sink_name,
- group->mutebyrt ? "on" : "off");
- }
- else {
- pa_log_debug("group '%s' is routed to '%s' due to "
- "mute-by-route muting is %s", group->name, sink_name,
- mute ? "on" : "off");
-
- group->mutebyrt = mute;
-
- if (!group->locmute) {
- for (sl = group->sinpls; sl != NULL; sl = sl->next) {
- sinp = sl->sink_input;
-
- pa_log_debug("move sink input '%s' to sink '%s' by "
- "mute-by-route",
- pa_sink_input_ext_get_name(sinp), sink_name);
-
- if (pa_sink_input_move_to(sinp, sink, TRUE) < 0)
- ret = -1;
- }
- }
- }
- }
-
- return ret;
-}
-
-static int mute_group_locally(struct userdata *u,
- struct pa_policy_group *group,
- int locmute)
-{
- struct pa_sink_input_list *sl;
- struct pa_sink_input *sinp;
- struct pa_sink_input_ext *ext;
- struct pa_sink *sink;
- char *sink_name;
- char *sinp_name;
- pa_volume_t volume;
- int mutebyrt;
- int mark;
- int mute;
- int percent;
- const char *prefix;
- const char *method;
- int ret = 0;
-
-
- if (locmute != group->locmute) {
- group->locmute = locmute;
-
- mutebyrt = group->flags & PA_POLICY_GROUP_FLAG_MUTE_BY_ROUTE;
- prefix = locmute ? "" : "un";
- method = mutebyrt ? " using mute-by-route" : "";
-
- pa_log_debug("group '%s' locally %smuted%s",group->name,prefix,method);
-
-
- for (sl = group->sinpls; sl != NULL; sl = sl->next) {
- sinp = sl->sink_input;
- ext = pa_sink_input_ext_lookup(u, sinp);
- mark = (ext && ext->local.mute);
- mute = mark ? !locmute : locmute;
- sink = mute ? u->nullsink->sink : group->sink;
-
- sink_name = sink ? pa_sink_ext_get_name(sink) : "<unknown sink>";
- sinp_name = pa_sink_input_ext_get_name(sinp);
-
- if (mutebyrt)
- volume = group->limit;
- else
- volume = mute ? 0 : (mark ? PA_VOLUME_NORM : group->limit);
-
- percent = (volume * 100) / PA_VOLUME_NORM;
-
-
- if (mutebyrt && sink && sink != sinp->sink) {
- pa_log_debug("moving stream '%s'/'%s' to sink '%s'",
- group->name, sinp_name, sink_name);
-
- if (pa_sink_input_move_to(sinp, sink, TRUE) < 0)
- ret = -1;
- else {
- pa_log_debug("stream '%s'/'%s' is now at sink '%s'",
- group->name, sinp_name, sink_name);
- }
- }
-
- pa_log_debug("set volume limit %d for sink input '%s'/'%s'",
- percent, group->name, sinp_name);
-
- if (pa_sink_input_ext_set_volume_limit(sinp, volume) < 0)
- ret = -1;
- else {
- pa_log_debug("now volume limit %d for sink input '%s'/'%s'",
- percent, group->name, sinp_name);
- }
- }
- }
-
- return ret;
-}
-
-
-static int cork_group(struct pa_policy_group *group, int corked)
-{
- struct pa_sink_input_list *sl;
- struct pa_sink_input *sinp;
-
-
- if (corked == group->corked) {
- pa_log_debug("group '%s' is already %s", group->name,
- corked ? "corked" : "uncorked");
- }
- else {
- group->corked = corked;
-
- for (sl = group->sinpls; sl; sl = sl->next) {
- sinp = sl->sink_input;
-
- pa_sink_input_cork(sinp, corked);
-
- pa_log_debug("sink input '%s' %s",
- pa_sink_input_ext_get_name(sinp),
- corked ? "corked" : "uncorked");
- }
- }
-
- return 0;
-}
-
-
-static struct pa_policy_group *
-find_group_by_name(struct pa_policy_groupset *gset, char *name,uint32_t *ridx)
-{
- struct pa_policy_group *group = NULL;
- uint32_t idx = hash_value(name);
-
- pa_assert(gset);
- pa_assert(name);
-
- for (group = gset->hash_tbl[idx]; group != NULL; group = group->next) {
- if (!strcmp(name, group->name))
- break;
- }
-
- if (ridx != NULL)
- *ridx = idx;
-
- return group;
-}
-
-
-static struct pa_sink *find_sink_by_type(struct userdata *u, char *type)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_sink *sink;
-
- pa_assert(u);
- pa_assert(type);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->sinks));
-
- while ((sink = pa_idxset_iterate(idxset, &state, NULL)) != NULL) {
- if (pa_classify_is_sink_typeof(u, sink, type, NULL))
- break;
- }
-
- return sink;
-}
-
-static struct pa_source *find_source_by_type(struct userdata *u, char *type)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_source *source;
-
- pa_assert(u);
- pa_assert(type);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->sources));
-
- while ((source = pa_idxset_iterate(idxset, &state, NULL)) != NULL) {
- if (pa_classify_is_source_typeof(u, source, type, NULL))
- break;
- }
-
- return source;
-}
-
-static uint32_t hash_value(char *s)
-{
- uint32_t hash = 0;
- unsigned char c;
-
- if (s) {
- while ((c = *s++) != '\0') {
- hash = 38501 * (hash + c);
- }
- }
-
- return hash & PA_POLICY_GROUP_HASH_MASK;
-}
-
-static pa_volume_t dB_to_sw_volume(int dB)
-{
- int idx = -dB;
- pa_volume_t volume;
-
- if (idx < 0)
- return PA_VOLUME_NORM;
-
- if (idx > (sizeof(dbtbl) / sizeof(dbtbl[0])))
- return PA_VOLUME_MUTED;
-
- return dbtbl[idx];
-}
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef foopolicygroupfoo
-#define foopolicygroupfoo
-
-#include <pulse/volume.h>
-#include <pulsecore/sink.h>
-
-#include "userdata.h"
-
-#define PA_POLICY_GROUP_HASH_BITS 6
-#define PA_POLICY_GROUP_HASH_DIM (1 << PA_POLICY_GROUP_HASH_BITS)
-#define PA_POLICY_GROUP_HASH_MASK (PA_POLICY_GROUP_HASH_DIM - 1)
-
-
-#define PA_POLICY_GROUP_BIT(b) (1UL << (b))
-#define PA_POLICY_GROUP_FLAG_NONE 0
-#define PA_POLICY_GROUP_FLAG_SET_SINK PA_POLICY_GROUP_BIT(0)
-#define PA_POLICY_GROUP_FLAG_SET_SOURCE PA_POLICY_GROUP_BIT(1)
-#define PA_POLICY_GROUP_FLAG_ROUTE_AUDIO PA_POLICY_GROUP_BIT(2)
-#define PA_POLICY_GROUP_FLAG_LIMIT_VOLUME PA_POLICY_GROUP_BIT(3)
-#define PA_POLICY_GROUP_FLAG_CORK_STREAM PA_POLICY_GROUP_BIT(4)
-#define PA_POLICY_GROUP_FLAG_MEDIA_NOTIFY PA_POLICY_GROUP_BIT(5)
-#define PA_POLICY_GROUP_FLAG_MUTE_BY_ROUTE PA_POLICY_GROUP_BIT(6)
-
-#define PA_POLICY_GROUP_FLAGS_CLIENT (PA_POLICY_GROUP_FLAG_LIMIT_VOLUME |\
- PA_POLICY_GROUP_FLAG_CORK_STREAM )
-
-#define PA_POLICY_GROUP_FLAGS_NOPOLICY PA_POLICY_GROUP_FLAG_NONE
-
-struct pa_sink_input_list {
- struct pa_sink_input_list *next;
- uint32_t index;
- struct pa_sink_input *sink_input;
-};
-
-struct pa_source_output_list {
- struct pa_source_output_list *next;
- uint32_t index;
- struct pa_source_output *source_output;
-};
-
-struct pa_policy_group {
- struct pa_policy_group *next; /* hash link*/
- uint32_t flags; /* or'ed PA_POLICY_GROUP_FLAG_x's*/
- char *name; /* name of the policy group */
- char *sinkname; /* name of the default sink */
- char *portname; /* name of the default port */
- struct pa_sink *sink; /* default sink for the group */
- uint32_t sinkidx; /* index of the default sink */
- char *srcname; /* name of the default source */
- struct pa_source *source; /* default source fror the group */
- uint32_t srcidx; /* index of the default source */
- pa_volume_t limit; /* volume limit for the group */
- int locmute; /* mute by local policy */
- int corked;
- int mutebyrt; /* muted by routing to null sink */
- struct pa_sink_input_list *sinpls; /* sink input list */
- struct pa_source_output_list *soutls; /* source output list */
- int sinpcnt; /* sink input counter */
- int soutcnt; /* source output counter */
-};
-
-struct pa_policy_groupset {
- struct pa_policy_group *dflt; /* default group */
- struct pa_policy_group *hash_tbl[PA_POLICY_GROUP_HASH_DIM];
-};
-
-enum pa_policy_route_class {
- pa_policy_route_unknown = 0,
- pa_policy_route_to_sink,
- pa_policy_route_to_source,
- pa_policy_route_max
-};
-
-
-struct pa_policy_groupset *pa_policy_groupset_new(struct userdata *);
-void pa_policy_groupset_free(struct pa_policy_groupset *);
-void pa_policy_groupset_update_default_sink(struct userdata *, uint32_t);
-void pa_policy_groupset_register_sink(struct userdata *, struct pa_sink *);
-void pa_policy_groupset_unregister_sink(struct userdata *, uint32_t);
-void pa_policy_groupset_register_source(struct userdata *, struct pa_source *);
-void pa_policy_groupset_unregister_source(struct userdata *, uint32_t);
-void pa_policy_groupset_create_default_group(struct userdata *, const char *);
-int pa_policy_groupset_restore_volume(struct userdata *, struct pa_sink *);
-
-struct pa_policy_group *pa_policy_group_new(struct userdata *, char*,
- char *, char *, uint32_t);
-void pa_policy_group_free(struct pa_policy_groupset *, char *);
-struct pa_policy_group *pa_policy_group_find(struct userdata *, char *);
-
-
-void pa_policy_group_insert_sink_input(struct userdata *, char *,
- struct pa_sink_input *, uint32_t);
-void pa_policy_group_remove_sink_input(struct userdata *, uint32_t);
-
-
-void pa_policy_group_insert_source_output(struct userdata *, char *,
- struct pa_source_output *);
-void pa_policy_group_remove_source_output(struct userdata *, uint32_t);
-
-int pa_policy_group_move_to(struct userdata *, char *,
- enum pa_policy_route_class, char *,
- char *, char *);
-int pa_policy_group_cork(struct userdata *u, char *, int);
-int pa_policy_group_volume_limit(struct userdata *, char *, uint32_t);
-struct pa_policy_group *pa_policy_group_scan(struct pa_policy_groupset *,
- void **);
-
-
-#endif
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulse/def.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/sink.h>
-
-#include "sink-ext.h"
-#include "index-hash.h"
-#include "classify.h"
-#include "context.h"
-#include "policy-group.h"
-#include "dbusif.h"
-#include "discover.h"
-
-/* hooks */
-static pa_hook_result_t sink_put(void *, void *, void *);
-static pa_hook_result_t sink_unlink(void *, void *, void *);
-
-static void handle_new_sink(struct userdata *, struct pa_sink *);
-static void handle_removed_sink(struct userdata *, struct pa_sink *);
-
-
-struct pa_null_sink *pa_sink_ext_init_null_sink(const char *name)
-{
- struct pa_null_sink *null_sink;
-
- if ((null_sink = malloc(sizeof(*null_sink))) != NULL) {
- memset(null_sink, 0, sizeof(*null_sink));
-
- /* sink.null is temporary to de-couple PA releases from ours */
- null_sink->name = pa_xstrdup(name ? name : /* "null" */ "sink.null");
- null_sink->sink = NULL;
- }
-
- return null_sink;
-}
-
-void pa_sink_ext_null_sink_free(struct pa_null_sink *null_sink)
-{
- if (null_sink != NULL) {
- pa_xfree(null_sink->name);
-
- pa_xfree(null_sink);
- }
-}
-
-struct pa_sink_evsubscr *pa_sink_ext_subscription(struct userdata *u)
-{
- pa_core *core;
- pa_hook *hooks;
- struct pa_sink_evsubscr *subscr;
- pa_hook_slot *put;
- pa_hook_slot *unlink;
-
- pa_assert(u);
- pa_assert_se((core = u->core));
-
- hooks = core->hooks;
-
- put = pa_hook_connect(hooks + PA_CORE_HOOK_SINK_PUT,
- PA_HOOK_LATE, sink_put, (void *)u);
- unlink = pa_hook_connect(hooks + PA_CORE_HOOK_SINK_UNLINK,
- PA_HOOK_LATE, sink_unlink, (void *)u);
-
-
- subscr = pa_xnew0(struct pa_sink_evsubscr, 1);
-
- subscr->put = put;
- subscr->unlink = unlink;
-
- return subscr;
-}
-
-void pa_sink_ext_subscription_free(struct pa_sink_evsubscr *subscr)
-{
- if (subscr != NULL) {
- pa_hook_slot_free(subscr->put);
- pa_hook_slot_free(subscr->unlink);
-
- pa_xfree(subscr);
- }
-}
-
-void pa_sink_ext_discover(struct userdata *u)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_sink *sink;
-
- pa_assert(u);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->sinks));
-
- while ((sink = pa_idxset_iterate(idxset, &state, NULL)) != NULL)
- handle_new_sink(u, sink);
-}
-
-
-struct pa_sink_ext *pa_sink_ext_lookup(struct userdata *u,struct pa_sink *sink)
-{
- struct pa_sink_ext *ext;
-
- pa_assert(u);
- pa_assert(sink);
-
- ext = pa_index_hash_lookup(u->hsnk, sink->index);
-
- return ext;
-}
-
-
-char *pa_sink_ext_get_name(struct pa_sink *sink)
-{
- return sink->name ? sink->name : (char *)"<unknown>";
-}
-
-int pa_sink_ext_set_ports(struct userdata *u, const char *type)
-{
- int ret = 0;
-
-#if PULSEAUDIO_HAS_PORTS
- pa_sink *sink;
- struct pa_classify_device_data *data;
- struct pa_classify_port_entry *port_entry;
- char *name;
- char *port;
- struct pa_sink_ext *ext;
- uint32_t idx;
-
- pa_assert(u);
- pa_assert(u->core);
-
- PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
- /* Check whether the port of this sink should be changed. */
- if (pa_classify_is_port_sink_typeof(u, sink, type, &data)) {
-
- pa_assert_se(port_entry = pa_hashmap_get(data->ports, sink->name));
- pa_assert_se(port = port_entry->port_name);
-
- name = pa_sink_ext_get_name(sink);
- ext = pa_sink_ext_lookup(u, sink);
-
- if (ext && ext->overridden_port) {
- free(ext->overridden_port);
- ext->overridden_port = pa_xstrdup(port);
- continue;
- }
-
- if (!sink->active_port || !pa_streq(port,sink->active_port->name)){
-
- if (!ext->overridden_port) {
- if (pa_sink_set_port(sink, port, FALSE) < 0) {
- ret = -1;
- pa_log("failed to set sink '%s' port to '%s'",
- name, port);
- }
- else {
- pa_log_debug("changed sink '%s' port to '%s'",
- name, port);
- }
- }
- continue;
- }
- }
- } /* for */
-#endif
-
- return ret;
-}
-
-void pa_sink_ext_set_volumes(struct userdata *u)
-{
- struct pa_sink *sink;
- struct pa_sink_ext *ext;
- uint32_t idx;
-
- pa_assert(u);
- pa_assert(u->core);
-
- PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
- ext = pa_sink_ext_lookup(u, sink);
-
- pa_assert(ext);
-
- if (ext->need_volume_setting) {
- pa_log_debug("set sink '%s' volume", pa_sink_ext_get_name(sink));
- pa_sink_set_volume(sink, NULL, TRUE, FALSE);
- ext->need_volume_setting = FALSE;
- }
- }
-}
-
-void pa_sink_ext_override_port(struct userdata *u, struct pa_sink *sink,
- char *port)
-{
- struct pa_sink_ext *ext;
- char *name;
- uint32_t idx;
- char *active_port;
-
- if (!sink || !u || !port)
- return;
-
- name = pa_sink_ext_get_name(sink);
- idx = sink->index;
- ext = pa_sink_ext_lookup(u, sink);
-
- if (ext == NULL) {
- pa_log("no extension found for sink '%s' (idx=%u)", name, idx);
- return;
- }
-
- active_port = sink->active_port ? sink->active_port->name : "";
-
- if (ext->overridden_port) {
- if (strcmp(port, active_port)) {
- pa_log_debug("attempt to multiple time to override "
- "port on sink '%s'", name);
- }
- }
- else {
- ext->overridden_port = pa_xstrdup(active_port);
-
- if (strcmp(port, active_port)) {
- if (pa_sink_set_port(sink, port, FALSE) < 0)
- pa_log("failed to override sink '%s' port to '%s'", name,port);
- else
- pa_log_debug("overrode sink '%s' port to '%s'", name, port);
- }
- }
-}
-
-void pa_sink_ext_restore_port(struct userdata *u, struct pa_sink *sink)
-{
- struct pa_sink_ext *ext;
- char *name;
- uint32_t idx;
- char *active_port;
- char *overridden_port;
-
- if (!sink || !u)
- return;
-
- name = pa_sink_ext_get_name(sink);
- idx = sink->index;
- ext = pa_sink_ext_lookup(u, sink);
-
- if (ext == NULL) {
- pa_log("no extension found for sink '%s' (idx=%u)", name, idx);
- return;
- }
-
- active_port = sink->active_port ? sink->active_port->name : "";
- overridden_port = ext->overridden_port;
-
- if (overridden_port) {
- if (strcmp(overridden_port, active_port)) {
- if (pa_sink_set_port(sink, overridden_port, FALSE) < 0) {
- pa_log("failed to restore sink '%s' port to '%s'",
- name, overridden_port);
- }
- else {
- pa_log_debug("restore sink '%s' port to '%s'",
- name, overridden_port);
- }
- }
-
- pa_xfree(overridden_port);
- ext->overridden_port = NULL;
- }
-}
-
-static pa_hook_result_t sink_put(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_sink *sink = (struct pa_sink *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_new_sink(u, sink);
-
- return PA_HOOK_OK;
-}
-
-
-static pa_hook_result_t sink_unlink(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_sink *sink = (struct pa_sink *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_removed_sink(u, sink);
-
- return PA_HOOK_OK;
-}
-
-
-static void handle_new_sink(struct userdata *u, struct pa_sink *sink)
-{
- char *name;
- uint32_t idx;
- char buf[1024];
- int len;
- int ret;
- int is_null_sink;
- struct pa_null_sink *ns;
- struct pa_sink_ext *ext;
-
- if (sink && u) {
- name = pa_sink_ext_get_name(sink);
- idx = sink->index;
- len = pa_classify_sink(u, sink, 0,0, buf, sizeof(buf));
- ns = u->nullsink;
-
- if (strcmp(name, ns->name))
- is_null_sink = FALSE;
- else {
- ns->sink = sink;
- pa_log_debug("new sink '%s' (idx=%d) will be used to "
- "mute-by-route", name, idx);
- is_null_sink = TRUE;
- }
-
- pa_policy_context_register(u, pa_policy_object_sink, name, sink);
-
- pa_discover_add_sink(u, sink);
-
- if (len <= 0) {
- if (!is_null_sink)
- pa_log_debug("new sink '%s' (idx=%d)", name, idx);
- }
- else {
- ret = pa_proplist_sets(sink->proplist,
- PA_PROP_POLICY_DEVTYPELIST, buf);
-
- if (ret < 0) {
- pa_log("failed to set property '%s' on sink '%s'",
- PA_PROP_POLICY_DEVTYPELIST, name);
- }
- else {
- pa_log_debug("new sink '%s' (idx=%d) (type %s)",
- name, idx, buf);
-
- ext = pa_xmalloc0(sizeof(struct pa_sink_ext));
- pa_index_hash_add(u->hsnk, idx, ext);
-
- pa_policy_groupset_update_default_sink(u, PA_IDXSET_INVALID);
- pa_policy_groupset_register_sink(u, sink);
-
- len = pa_classify_sink(u, sink, PA_POLICY_DISABLE_NOTIFY,0,
- buf, sizeof(buf));
- if (len > 0) {
- pa_policy_send_device_state(u, PA_POLICY_CONNECTED, buf);
- }
- }
- }
- }
-}
-
-static void handle_removed_sink(struct userdata *u, struct pa_sink *sink)
-{
- char *name;
- uint32_t idx;
- char buf[1024];
- int len;
- struct pa_null_sink *ns;
- struct pa_sink_ext *ext;
-
- if (sink && u) {
- name = pa_sink_ext_get_name(sink);
- idx = sink->index;
- len = pa_classify_sink(u, sink, 0,0, buf, sizeof(buf));
- ns = u->nullsink;
-
- if (ns->sink == sink) {
- pa_log_debug("cease to use sink '%s' (idx=%u) to mute-by-route",
- name, idx);
-
- /* TODO: move back the streams of this sink to their
- original place */
-
- ns->sink = NULL;
- }
-
- pa_policy_context_unregister(u, pa_policy_object_sink, name, sink,idx);
-
- if (len <= 0)
- pa_log_debug("remove sink '%s' (idx=%u)", name, idx);
- else {
- pa_log_debug("remove sink '%s' (idx=%d, type=%s)", name,idx, buf);
-
- pa_policy_groupset_update_default_sink(u, idx);
- pa_policy_groupset_unregister_sink(u, idx);
-
- if ((ext = pa_index_hash_remove(u->hsnk, idx)) == NULL)
- pa_log("no extension found for sink '%s' (idx=%u)",name,idx);
- else {
- pa_xfree(ext->overridden_port);
- pa_xfree(ext);
- }
-
- len = pa_classify_sink(u, sink, PA_POLICY_DISABLE_NOTIFY,0,
- buf, sizeof(buf));
-
- if (len > 0) {
- pa_policy_send_device_state(u, PA_POLICY_DISCONNECTED, buf);
- }
- }
- }
-}
-
-void pa_policy_send_device_state(struct userdata *u, const char *state,
- char *typelist)
-{
-#define MAX_TYPE 256
-
- char *types[MAX_TYPE];
- int ntype;
- char buf[1024];
- char *p, *q, c;
-
- if (typelist && typelist[0]) {
-
- ntype = 0;
-
- p = typelist - 1;
- q = buf;
-
- do {
- p++;
-
- if (ntype < MAX_TYPE)
- types[ntype] = q;
- else {
- pa_log("%s() list overflow", __FUNCTION__);
- return;
- }
-
- while ((c = *p) != ' ' && c != '\0') {
- if (q < buf + sizeof(buf)-1)
- *q++ = *p++;
- else {
- pa_log("%s() buffer overflow", __FUNCTION__);
- return;
- }
- }
- *q++ = '\0';
- ntype++;
-
- } while (*p);
-
- pa_policy_dbusif_send_device_state(u, (char *)state, types, ntype);
- }
-
-#undef MAX_TYPE
-}
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef foosinkextfoo
-#define foosinkextfoo
-
-#include "userdata.h"
-
-struct pa_sink;
-
-struct pa_null_sink {
- char *name;
- struct pa_sink *sink;
-};
-
-struct pa_sink_evsubscr {
- pa_hook_slot *put;
- pa_hook_slot *unlink;
-};
-
-struct pa_sink_ext {
- char *overridden_port;
- int need_volume_setting;
-};
-
-struct pa_null_sink *pa_sink_ext_init_null_sink(const char *);
-void pa_sink_ext_null_sink_free(struct pa_null_sink *);
-struct pa_sink_evsubscr *pa_sink_ext_subscription(struct userdata *);
-void pa_sink_ext_subscription_free(struct pa_sink_evsubscr *);
-void pa_sink_ext_discover(struct userdata *);
-struct pa_sink_ext *pa_sink_ext_lookup(struct userdata *, struct pa_sink *);
-char *pa_sink_ext_get_name(struct pa_sink *);
-int pa_sink_ext_set_ports(struct userdata *, const char *);
-void pa_sink_ext_set_volumes(struct userdata *);
-void pa_sink_ext_override_port(struct userdata *, struct pa_sink *, char *);
-void pa_sink_ext_restore_port(struct userdata *, struct pa_sink *);
-
-void pa_policy_send_device_state(struct userdata *, const char *, char *);
-
-#endif /* foosinkextfoo */
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulse/def.h>
-#include <pulse/proplist.h>
-#include <pulse/volume.h>
-#include <pulsecore/sink.h>
-#include <pulsecore/sink-input.h>
-
-#include "userdata.h"
-#include "index-hash.h"
-#include "policy-group.h"
-#include "sink-input-ext.h"
-#include "sink-ext.h"
-#include "classify.h"
-#include "context.h"
-#include "discover.h"
-
-/* hooks */
-static pa_hook_result_t sink_input_neew(void *, void *, void *);
-static pa_hook_result_t sink_input_put(void *, void *, void *);
-static pa_hook_result_t sink_input_unlink(void *, void *, void *);
-
-static void handle_new_sink_input(struct userdata *, struct pa_sink_input *);
-static void handle_removed_sink_input(struct userdata *,
- struct pa_sink_input *);
-
-struct pa_sinp_evsubscr *pa_sink_input_ext_subscription(struct userdata *u)
-{
- pa_core *core;
- pa_hook *hooks;
- struct pa_sinp_evsubscr *subscr;
- pa_hook_slot *neew;
- pa_hook_slot *put;
- pa_hook_slot *unlink;
-
- pa_assert(u);
- pa_assert_se((core = u->core));
-
- hooks = core->hooks;
-
- neew = pa_hook_connect(hooks + PA_CORE_HOOK_SINK_INPUT_NEW,
- PA_HOOK_EARLY, sink_input_neew, (void *)u);
- put = pa_hook_connect(hooks + PA_CORE_HOOK_SINK_INPUT_PUT,
- PA_HOOK_LATE, sink_input_put, (void *)u);
- unlink = pa_hook_connect(hooks + PA_CORE_HOOK_SINK_INPUT_UNLINK,
- PA_HOOK_LATE, sink_input_unlink, (void *)u);
-
-
- subscr = pa_xnew0(struct pa_sinp_evsubscr, 1);
-
- subscr->neew = neew;
- subscr->put = put;
- subscr->unlink = unlink;
-
- return subscr;
-}
-
-void pa_sink_input_ext_subscription_free(struct pa_sinp_evsubscr *subscr)
-{
- if (subscr != NULL) {
- pa_hook_slot_free(subscr->neew);
- pa_hook_slot_free(subscr->put);
- pa_hook_slot_free(subscr->unlink);
-
- pa_xfree(subscr);
- }
-}
-
-void pa_sink_input_ext_discover(struct userdata *u)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_sink_input *sinp;
-
- pa_assert(u);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->sink_inputs));
-
- while ((sinp = pa_idxset_iterate(idxset, &state, NULL)) != NULL)
- handle_new_sink_input(u, sinp);
-}
-
-struct pa_sink_input_ext *pa_sink_input_ext_lookup(struct userdata *u,
- struct pa_sink_input *sinp)
-{
- struct pa_sink_input_ext *ext;
-
- pa_assert(u);
- pa_assert(sinp);
-
- ext = pa_index_hash_lookup(u->hsi, sinp->index);
-
- return ext;
-}
-
-
-int pa_sink_input_ext_set_policy_group(struct pa_sink_input *sinp,
- char *group)
-{
- int ret;
-
- assert(sinp);
-
- if (group)
- ret = pa_proplist_sets(sinp->proplist, PA_PROP_POLICY_GROUP, group);
- else
- ret = pa_proplist_unset(sinp->proplist, PA_PROP_POLICY_GROUP);
-
- return ret;
-}
-
-char *pa_sink_input_ext_get_policy_group(struct pa_sink_input *sinp)
-{
- const char *group;
-
- pa_assert(sinp);
-
- group = pa_proplist_gets(sinp->proplist, PA_PROP_POLICY_GROUP);
-
- if (group == NULL)
- group = PA_POLICY_DEFAULT_GROUP_NAME;
-
- return (char *)group;
-}
-
-char *pa_sink_input_ext_get_name(struct pa_sink_input *sinp)
-{
- const char *name;
-
- assert(sinp);
-
- name = pa_proplist_gets(sinp->proplist, PA_PROP_MEDIA_NAME);
-
- if (name == NULL)
- name = "<unknown>";
-
- return (char *)name;
-}
-
-
-int pa_sink_input_ext_set_volume_limit(struct pa_sink_input *sinp,
- pa_volume_t limit)
-{
- pa_sink *sink;
- int retval;
- uint64_t limit64;
- pa_volume_t value;
- pa_cvolume *factor;
- pa_cvolume *real;
- int changed;
- int i;
-
- pa_assert(sinp);
- pa_assert_se((sink = sinp->sink));
-
- retval = 0;
-
- if (limit == 0)
- pa_sink_input_set_mute(sinp, TRUE, TRUE);
- else {
- pa_sink_input_set_mute(sinp, FALSE, TRUE);
-
- if (limit > PA_VOLUME_NORM)
- limit = PA_VOLUME_NORM;
-
- factor = &sinp->volume_factor;
- real = &sinp->real_ratio;
- limit64 = (uint64_t)limit * (uint64_t)PA_VOLUME_NORM;
- changed = FALSE;
-
- if (real->channels != factor->channels) {
- pa_log_debug("channel number mismatch");
- retval = -1;
- }
- else {
- for (i = 0; i < factor->channels; i++) {
- if (limit < real->values[i])
- value = limit64 / (uint64_t)real->values[i];
- else
- value = PA_VOLUME_NORM;
-
- if (value != factor->values[i]) {
- changed = 1;
- factor->values[i] = value;
- }
- }
-
- if (changed) {
- if (sink->flags & PA_SINK_FLAT_VOLUME)
- retval = 1;
- else {
- pa_sw_cvolume_multiply(&sinp->soft_volume, real, factor);
- pa_asyncmsgq_send(sink->asyncmsgq, PA_MSGOBJECT(sinp),
- PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME,
- NULL, 0, NULL);
- }
- }
- }
- }
-
- return retval;
-}
-
-
-
-static pa_hook_result_t sink_input_neew(void *hook_data, void *call_data,
- void *slot_data)
-{
- static uint32_t route_flags = PA_POLICY_GROUP_FLAG_SET_SINK |
- PA_POLICY_GROUP_FLAG_ROUTE_AUDIO;
- static pa_volume_t max_volume = PA_VOLUME_NORM;
-
-
- struct pa_sink_input_new_data
- *data = (struct pa_sink_input_new_data *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
- uint32_t flags;
- char *group_name;
- const char *sinp_name;
- char *sink_name;
- int group_volume;
- int local_route;
- int local_volume;
- pa_cvolume group_limit;
- struct pa_policy_group *group;
-
- pa_assert(u);
- pa_assert(data);
-
- if ((group_name = pa_classify_sink_input_by_data(u,data,&flags)) != NULL &&
- (group = pa_policy_group_find(u, group_name) ) != NULL ){
-
- if (group->sink != NULL) {
- sinp_name = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_NAME);
-
- if (!sinp_name)
- sinp_name = "<unknown>";
-
- group_volume = group->flags & PA_POLICY_GROUP_FLAG_LIMIT_VOLUME;
- local_route = flags & PA_POLICY_LOCAL_ROUTE;
- local_volume = flags & PA_POLICY_LOCAL_VOLMAX;
-
- if (group->mutebyrt && !local_route) {
- sink_name = u->nullsink->name;
-
- pa_log_debug("force stream '%s'/'%s' to sink '%s' due to "
- "mute-by-route", group_name,sinp_name, sink_name);
-
- data->sink = u->nullsink->sink;
- }
- else if (group->flags & route_flags) {
- sink_name = pa_sink_ext_get_name(group->sink);
-
- pa_log_debug("force stream '%s'/'%s' to sink '%s'",
- group_name, sinp_name, sink_name);
-
- data->sink = group->sink;
- }
-
- if (local_volume) {
- pa_log_debug("force stream '%s'/'%s' volume to %d",
- group_name, sinp_name,
- (max_volume * 100) / PA_VOLUME_NORM);
-
- pa_cvolume_set(&data->volume, data->channel_map.channels,
- max_volume);
-
- data->volume_is_set = TRUE;
- data->save_volume = FALSE;
- }
- else if (group_volume && !group->mutebyrt &&
- group->limit > 0 && group->limit < PA_VOLUME_NORM)
- {
- pa_log_debug("set stream '%s'/'%s' volume factor to %d",
- group_name, sinp_name,
- (group->limit * 100) / PA_VOLUME_NORM);
-
- pa_cvolume_set(&group_limit, data->channel_map.channels,
- group->limit);
-
- pa_sink_input_new_data_apply_volume_factor(data, &group_limit);
- }
- }
-
- }
-
-
- return PA_HOOK_OK;
-}
-
-
-static pa_hook_result_t sink_input_put(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_sink_input *sinp = (struct pa_sink_input *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_new_sink_input(u, sinp);
-
- return PA_HOOK_OK;
-}
-
-
-static pa_hook_result_t sink_input_unlink(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_sink_input *sinp = (struct pa_sink_input *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_removed_sink_input(u, sinp);
-
- return PA_HOOK_OK;
-}
-
-static void handle_new_sink_input(struct userdata *u,
- struct pa_sink_input *sinp)
-{
- struct pa_sink_input_ext *ext;
- uint32_t idx;
- char *snam;
- char *gnam;
- uint32_t flags;
-
- if (sinp && u) {
- idx = sinp->index;
- snam = pa_sink_input_ext_get_name(sinp);
- gnam = pa_classify_sink_input(u, sinp, &flags);
-
- ext = pa_xmalloc0(sizeof(struct pa_sink_input_ext));
- ext->local.route = (flags & PA_POLICY_LOCAL_ROUTE) ? TRUE : FALSE;
- ext->local.mute = (flags & PA_POLICY_LOCAL_MUTE ) ? TRUE : FALSE;
- pa_index_hash_add(u->hsi, idx, ext);
-
- pa_policy_context_register(u, pa_policy_object_sink_input, snam, sinp);
- pa_policy_group_insert_sink_input(u, gnam, sinp, flags);
-
- pa_log_debug("new sink_input %s (idx=%d) (group=%s)", snam, idx, gnam);
- }
-}
-
-
-static void handle_removed_sink_input(struct userdata *u,
- struct pa_sink_input *sinp)
-{
- struct pa_sink_input_ext *ext;
- struct pa_sink *sink;
- uint32_t idx;
- char *snam;
- char *gnam;
- uint32_t flags;
-
- if (sinp && u) {
- idx = sinp->index;
- sink = sinp->sink;
- snam = pa_sink_input_ext_get_name(sinp);
- gnam = pa_classify_sink_input(u, sinp, &flags);
-
- if (flags & PA_POLICY_LOCAL_ROUTE)
- pa_sink_ext_restore_port(u, sink);
-
- if (flags & PA_POLICY_LOCAL_MUTE)
- pa_policy_groupset_restore_volume(u, sink);
-
- pa_policy_context_unregister(u, pa_policy_object_sink_input,
- snam, sinp, sinp->index);
- pa_policy_group_remove_sink_input(u, sinp->index);
-
-
- if ((ext = pa_index_hash_remove(u->hsi, idx)) == NULL)
- pa_log("no extension found for sink-input '%s' (idx=%u)",snam,idx);
- else {
- pa_xfree(ext);
- }
-
- pa_log_debug("removed sink_input '%s' (idx=%d) (group=%s)",
- snam, idx, gnam);
- }
-}
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef foosinkinputextfoo
-#define foosinkinputextfoo
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <pulse/volume.h>
-#include <pulsecore/sink-input.h>
-#include <pulsecore/sink.h>
-#include <pulsecore/core-subscribe.h>
-
-
-#include "userdata.h"
-
-struct pa_sinp_evsubscr {
- pa_hook_slot *neew;
- pa_hook_slot *put;
- pa_hook_slot *unlink;
-};
-
-struct pa_sink_input_ext {
- struct {
- int route;
- int mute;
- } local; /* local policies */
-};
-
-struct pa_sinp_evsubscr *pa_sink_input_ext_subscription(struct userdata *);
-void pa_sink_input_ext_subscription_free(struct pa_sinp_evsubscr *);
-void pa_sink_input_ext_discover(struct userdata *);
-struct pa_sink_input_ext *pa_sink_input_ext_lookup(struct userdata *,
- struct pa_sink_input *);
-int pa_sink_input_ext_set_policy_group(struct pa_sink_input *, char *);
-char *pa_sink_input_ext_get_policy_group(struct pa_sink_input *);
-char *pa_sink_input_ext_get_name(struct pa_sink_input *);
-int pa_sink_input_ext_set_volume_limit(struct pa_sink_input *, pa_volume_t);
-
-#endif
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulse/def.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/source.h>
-
-#include "source-ext.h"
-#include "classify.h"
-#include "context.h"
-#include "policy-group.h"
-#include "dbusif.h"
-#include "discover.h"
-
-/* this included for the sake of pa_policy_send_device_state()
- which is temporarily hosted by sink-ext.c*/
-#include "sink-ext.h"
-
-/* hooks */
-static pa_hook_result_t source_put(void *, void *, void *);
-static pa_hook_result_t source_unlink(void *, void *, void *);
-
-static void handle_new_source(struct userdata *, struct pa_source *);
-static void handle_removed_source(struct userdata *, struct pa_source *);
-
-
-
-struct pa_source_evsubscr *pa_source_ext_subscription(struct userdata *u)
-{
- pa_core *core;
- pa_hook *hooks;
- struct pa_source_evsubscr *subscr;
- pa_hook_slot *put;
- pa_hook_slot *unlink;
-
- pa_assert(u);
- pa_assert_se((core = u->core));
-
- hooks = core->hooks;
-
- put = pa_hook_connect(hooks + PA_CORE_HOOK_SOURCE_PUT,
- PA_HOOK_LATE, source_put, (void *)u);
- unlink = pa_hook_connect(hooks + PA_CORE_HOOK_SOURCE_UNLINK,
- PA_HOOK_LATE, source_unlink, (void *)u);
-
-
- subscr = pa_xnew0(struct pa_source_evsubscr, 1);
-
- subscr->put = put;
- subscr->unlink = unlink;
-
- return subscr;
-}
-
-void pa_source_ext_subscription_free(struct pa_source_evsubscr *subscr)
-{
- if (subscr != NULL) {
- pa_hook_slot_free(subscr->put);
- pa_hook_slot_free(subscr->unlink);
-
- pa_xfree(subscr);
- }
-}
-
-void pa_source_ext_discover(struct userdata *u)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_source *source;
-
- pa_assert(u);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->sources));
-
- while ((source = pa_idxset_iterate(idxset, &state, NULL)) != NULL)
- handle_new_source(u, source);
-}
-
-
-char *pa_source_ext_get_name(struct pa_source *source)
-{
- return source->name ? source->name : (char *)"<unknown>";
-}
-
-int pa_source_ext_set_mute(struct userdata *u, char *type, int mute)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_source *source;
- char *name;
- pa_bool_t current_mute;
-
- pa_assert(u);
- pa_assert(type);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->sources));
-
- while ((source = pa_idxset_iterate(idxset, &state, NULL)) != NULL) {
- if (pa_classify_is_source_typeof(u, source, type, NULL)) {
- name = pa_source_ext_get_name(source);
- current_mute = pa_source_get_mute(source, 0);
-
- if ((current_mute && mute) || (!current_mute && !mute)) {
- pa_log_debug("%s() source '%s' type '%s' is already %smuted",
- __FUNCTION__, name, type, mute ? "" : "un");
- }
- else {
- pa_log_debug("%s() %smute source '%s' type '%s'",
- __FUNCTION__, mute ? "" : "un", name, type);
-
-#if PULSEAUDIO_HAS_PORTS
- pa_source_set_mute(source, mute, TRUE);
-#else
- pa_source_set_mute(source, mute);
-#endif
- }
-
- return 0;
- }
- }
-
-
- return -1;
-}
-
-int pa_source_ext_set_ports(struct userdata *u, const char *type)
-{
- int ret = 0;
-
-#if PULSEAUDIO_HAS_PORTS
- pa_source *source;
- struct pa_classify_device_data *data;
- uint32_t idx;
-
- pa_assert(u);
- pa_assert(u->core);
-
- PA_IDXSET_FOREACH(source, u->core->sources, idx) {
- /* Check whether the port of this source should be changed. */
- if (pa_classify_is_port_source_typeof(u, source, type, &data)) {
- struct pa_classify_port_entry *port_entry;
-
- pa_assert_se(port_entry = pa_hashmap_get(data->ports,
- source->name));
-
- if (!source->active_port ||
- !pa_streq(port_entry->port_name,
- source->active_port->name)) {
-
- if (pa_source_set_port(source, port_entry->port_name,
- FALSE) < 0) {
- ret = -1;
- pa_log("failed to set source '%s' port to '%s'",
- source->name, port_entry->port_name);
- }
- else {
- pa_log_debug("changed source '%s' port to '%s'",
- source->name, port_entry->port_name);
- }
- }
- }
- }
-#endif
-
- return ret;
-}
-
-static pa_hook_result_t source_put(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_source *source = (struct pa_source *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_new_source(u, source);
-
- return PA_HOOK_OK;
-}
-
-
-static pa_hook_result_t source_unlink(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_source *source = (struct pa_source *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_removed_source(u, source);
-
- return PA_HOOK_OK;
-}
-
-static void handle_new_source(struct userdata *u, struct pa_source *source)
-{
- char *name;
- uint32_t idx;
- char buf[1024];
- int len;
- int ret;
-
- if (source && u) {
- name = pa_source_ext_get_name(source);
- idx = source->index;
- len = pa_classify_source(u, source, 0,0, buf, sizeof(buf));
-
-
- if (len <= 0)
- pa_log_debug("new source '%s' (idx=%d)", name, idx);
- else {
- ret = pa_proplist_sets(source->proplist,
- PA_PROP_POLICY_DEVTYPELIST, buf);
-
- pa_policy_context_register(u,pa_policy_object_source,name,source);
-
- pa_discover_add_source(u, source);
-
- if (ret < 0) {
- pa_log("failed to set property '%s' on source '%s'",
- PA_PROP_POLICY_DEVTYPELIST, name);
- }
- else {
- pa_log_debug("new source '%s' (idx=%d type %s)",
- name, idx, buf);
-#if 0
- pa_policy_groupset_update_default_source(u, PA_IDXSET_INVALID);
-#endif
- pa_policy_groupset_register_source(u, source);
-
- len = pa_classify_source(u, source, PA_POLICY_DISABLE_NOTIFY,0,
- buf, sizeof(buf));
- if (len > 0) {
- pa_policy_send_device_state(u, PA_POLICY_CONNECTED, buf);
- }
- }
- }
- }
-}
-
-static void handle_removed_source(struct userdata *u, struct pa_source *source)
-{
- char *name;
- uint32_t idx;
- char buf[1024];
- int len;
-
- if (source && u) {
- name = pa_source_ext_get_name(source);
- idx = source->index;
- len = pa_classify_source(u, source, 0,0, buf, sizeof(buf));
-
- pa_policy_context_unregister(u, pa_policy_object_source,
- name, source, idx);
-
- pa_discover_remove_source(u, source);
-
- if (len <= 0)
- pa_log_debug("remove source '%s' (idx=%d)", name, idx);
- else {
- pa_log_debug("remove source '%s' (idx=%d, type=%s)", name,idx,buf);
-
-#if 0
- pa_policy_groupset_update_default_source(u, idx);
-#endif
- pa_policy_groupset_unregister_source(u, idx);
-
- len = pa_classify_source(u, source, PA_POLICY_DISABLE_NOTIFY,0,
- buf, sizeof(buf));
- if (len > 0) {
- pa_policy_send_device_state(u, PA_POLICY_DISCONNECTED, buf);
- }
- }
- }
-}
-
-
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef foosourceextfoo
-#define foosourceextfoo
-
-#include "userdata.h"
-
-struct pa_source;
-
-struct pa_source_evsubscr {
- pa_hook_slot *put;
- pa_hook_slot *unlink;
-};
-
-struct pa_source_evsubscr *pa_source_ext_subscription(struct userdata *);
-void pa_source_ext_subscription_free(struct pa_source_evsubscr *);
-void pa_source_ext_discover(struct userdata *);
-char *pa_source_ext_get_name(struct pa_source *);
-int pa_source_ext_set_mute(struct userdata *, char *, int);
-int pa_source_ext_set_ports(struct userdata *, const char *);
-
-#endif /* foosourceextfoo */
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <pulsecore/pulsecore-config.h>
-
-#include <pulse/def.h>
-#include <pulse/proplist.h>
-#include <pulsecore/sink.h>
-#include <pulsecore/sink-input.h>
-
-#include "policy-group.h"
-#include "source-ext.h"
-#include "source-output-ext.h"
-#include "classify.h"
-#include "context.h"
-
-
-/* hooks */
-static pa_hook_result_t source_output_neew(void *, void *, void *);
-static pa_hook_result_t source_output_put(void *, void *, void *);
-static pa_hook_result_t source_output_unlink(void *, void *, void *);
-
-static void handle_new_source_output(struct userdata *,
- struct pa_source_output *);
-static void handle_removed_source_output(struct userdata *,
- struct pa_source_output *);
-
-
-struct pa_sout_evsubscr *pa_source_output_ext_subscription(struct userdata *u)
-{
- pa_core *core;
- pa_hook *hooks;
- struct pa_sout_evsubscr *subscr;
- pa_hook_slot *neew;
- pa_hook_slot *put;
- pa_hook_slot *unlink;
-
- pa_assert(u);
- pa_assert_se((core = u->core));
-
- hooks = core->hooks;
-
- neew = pa_hook_connect(hooks + PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
- PA_HOOK_EARLY, source_output_neew, (void *)u);
- put = pa_hook_connect(hooks + PA_CORE_HOOK_SOURCE_OUTPUT_PUT,
- PA_HOOK_LATE, source_output_put, (void *)u);
- unlink = pa_hook_connect(hooks + PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK,
- PA_HOOK_LATE, source_output_unlink, (void *)u);
-
- subscr = pa_xnew0(struct pa_sout_evsubscr, 1);
-
- subscr->neew = neew;
- subscr->put = put;
- subscr->unlink = unlink;
-
-
- return subscr;
-}
-
-void pa_source_output_ext_subscription_free(struct pa_sout_evsubscr *subscr)
-{
- if (subscr != NULL) {
- pa_hook_slot_free(subscr->neew);
- pa_hook_slot_free(subscr->put);
- pa_hook_slot_free(subscr->unlink);
-
- pa_xfree(subscr);
- }
-}
-
-void pa_source_output_ext_discover(struct userdata *u)
-{
- void *state = NULL;
- pa_idxset *idxset;
- struct pa_source_output *sout;
-
- pa_assert(u);
- pa_assert(u->core);
- pa_assert_se((idxset = u->core->source_outputs));
-
- while ((sout = pa_idxset_iterate(idxset, &state, NULL)) != NULL)
- handle_new_source_output(u, sout);
-}
-
-int pa_source_output_ext_set_policy_group(struct pa_source_output *sout,
- char *group)
-{
- int ret;
-
- pa_assert(sout);
-
- if (group)
- ret = pa_proplist_sets(sout->proplist, PA_PROP_POLICY_GROUP, group);
- else
- ret = pa_proplist_unset(sout->proplist, PA_PROP_POLICY_GROUP);
-
- return ret;
-}
-
-char *pa_source_output_ext_get_policy_group(struct pa_source_output *sout)
-{
- const char *group;
-
- pa_assert(sout);
-
- group = pa_proplist_gets(sout->proplist, PA_PROP_POLICY_GROUP);
-
- if (group == NULL)
- group = PA_POLICY_DEFAULT_GROUP_NAME;
-
- return (char *)group;
-}
-
-char *pa_source_output_ext_get_name(struct pa_source_output *sout)
-{
- const char *name;
-
- pa_assert(sout);
-
- name = pa_proplist_gets(sout->proplist, PA_PROP_MEDIA_NAME);
-
- if (name == NULL)
- name = "<unknown>";
-
- return (char *)name;
-}
-
-
-static pa_hook_result_t source_output_neew(void *hook_data, void *call_data,
- void *slot_data)
-{
- static uint32_t route_flags = PA_POLICY_GROUP_FLAG_SET_SOURCE |
- PA_POLICY_GROUP_FLAG_ROUTE_AUDIO;
-
- struct pa_source_output_new_data
- *data = (struct pa_source_output_new_data *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
- char *group_name;
- const char *sout_name;
- char *source_name;
- struct pa_policy_group *group;
-
- if ((group_name = pa_classify_source_output_by_data(u, data)) != NULL &&
- (group = pa_policy_group_find(u, group_name) ) != NULL ){
-
- if (group->source != NULL && (group->flags & route_flags)) {
- sout_name = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_NAME);
- source_name = pa_source_ext_get_name(group->source);
-
- pa_log_debug("force source output '%s' to source '%s'",
- sout_name ? sout_name : "<unknown>", source_name);
-
- data->source = group->source;
- }
-
- }
-
-
- return PA_HOOK_OK;
-}
-
-
-static pa_hook_result_t source_output_put(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_source_output *sout = (struct pa_source_output *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_new_source_output(u, sout);
-
- return PA_HOOK_OK;
-}
-
-
-static pa_hook_result_t source_output_unlink(void *hook_data, void *call_data,
- void *slot_data)
-{
- struct pa_source_output *sout = (struct pa_source_output *)call_data;
- struct userdata *u = (struct userdata *)slot_data;
-
- handle_removed_source_output(u, sout);
-
- return PA_HOOK_OK;
-}
-
-
-static void handle_new_source_output(struct userdata *u,
- struct pa_source_output *sout)
-{
- char *snam;
- char *gnam;
-
- if (sout && u) {
- snam = pa_source_output_ext_get_name(sout);
- gnam = pa_classify_source_output(u, sout);
-
- pa_policy_context_register(u,pa_policy_object_source_output,snam,sout);
- pa_policy_group_insert_source_output(u, gnam, sout);
-
- pa_log_debug("new source_output %s (idx=%d) (group=%s)",
- snam, sout->index, gnam);
- }
-}
-
-
-static void handle_removed_source_output(struct userdata *u,
- struct pa_source_output *sout)
-{
- char *snam;
- char *gnam;
-
- if (sout && u) {
- snam = pa_source_output_ext_get_name(sout);
- gnam = pa_classify_source_output(u, sout);
-
- pa_policy_context_unregister(u, pa_policy_object_source_output,
- snam, sout, sout->index);
- pa_policy_group_remove_source_output(u, sout->index);
-
- pa_log_debug("removed source_output %s (idx=%d) (group=%s)",
- snam, sout->index, gnam);
- }
-}
-
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */
+++ /dev/null
-#ifndef foosourceoutputextfoo
-#define foosourceoutputextfoo
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <pulse/volume.h>
-#include <pulsecore/source-output.h>
-#include <pulsecore/source.h>
-#include <pulsecore/core-subscribe.h>
-
-
-#include "userdata.h"
-
-struct pa_sout_evsubscr {
- pa_hook_slot *neew;
- pa_hook_slot *put;
- pa_hook_slot *unlink;
-};
-
-struct pa_sout_evsubscr *pa_source_output_ext_subscription(struct userdata *);
-void pa_source_output_ext_subscription_free(struct pa_sout_evsubscr *);
-void pa_source_output_ext_discover(struct userdata *);
-int pa_source_output_ext_set_policy_group(struct pa_source_output *, char *);
-char *pa_source_output_ext_get_policy_group(struct pa_source_output *);
-char *pa_source_output_ext_get_name(struct pa_source_output *);
-
-#endif
-
-/*
- * Local Variables:
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
- */