uint32_t index;
} stream_uncork_t;
-static const char combine_pattern[] = "Simultaneous output on ";
-static const char loopback_pattern[] = "Loopback from ";
+static const char combine_pattern[] = "Simultaneous output on ";
+static const char loopback_outpatrn[] = "Loopback from ";
+static const char loopback_inpatrn[] = "Loopback to ";
static void handle_alsa_card(struct userdata *, pa_card *);
static void handle_bluetooth_card(struct userdata *, pa_card *);
static pa_sink *make_output_prerouting(struct userdata *, mir_node *,
pa_channel_map *, const char *,
mir_node **);
+static pa_source *make_input_prerouting(struct userdata *, mir_node *,
+ const char *, mir_node **);
static mir_node_type get_stream_routing_class(pa_proplist *);
pa_log_debug("node for '%s' found (key %s). Updating with sink data",
node->paname, node->key);
node->paidx = sink->index;
+ node->available = TRUE;
pa_discover_add_node_to_ptr_hash(u, sink, node);
if ((loopback_role = pa_classify_loopback_stream(node))) {
pa_log_debug("can't find node for sink (name '%s')", name);
else {
pa_log_debug("node found for '%s'. Reseting sink data", name);
+ schedule_source_cleanup(u, node);
node->paidx = PA_IDXSET_INVALID;
pa_hashmap_remove(discover->nodes.byptr, sink);
node->available = FALSE;
else {
if (!u->state.profile)
- schedule_deferred_routing(u);
+ schedule_deferred_routing(u);
}
}
else {
pa_log_debug("node for '%s' found. Updating with source data",
node->amname);
node->paidx = source->index;
+ node->available = TRUE;
pa_discover_add_node_to_ptr_hash(u, source, node);
if ((loopback_role = pa_classify_loopback_stream(node))) {
if (!(ns = pa_utils_get_null_sink(u))) {
pa_discover *discover;
mir_node *node;
char *name;
+ mir_node_type type;
pa_assert(u);
pa_assert(source);
schedule_source_cleanup(u, node);
node->paidx = PA_IDXSET_INVALID;
pa_hashmap_remove(discover->nodes.byptr, source);
+
+ type = node->type;
+
+ if (source->card) {
+ if (type != mir_bluetooth_sco)
+ node->available = FALSE;
+ else {
+ if (!u->state.profile)
+ schedule_deferred_routing(u);
+ }
+ }
+ else {
+ pa_log_info("currently we do not support statically "
+ "loaded sources");
+ }
}
}
pa_log_debug("Seems to be a combine stream. Nothing to do ...");
return;
}
- if (!strncmp(media, loopback_pattern, sizeof(loopback_pattern)-1)) {
+ if (!strncmp(media, loopback_outpatrn, sizeof(loopback_outpatrn)-1)) {
pa_log_debug("Seems to be a loopback stream. Nothing to do ...");
return;
}
name = pa_utils_get_sink_input_name(sinp);
- pa_log_debug("registering stream '%s'", name);
+ pa_log_debug("registering input stream '%s'", name);
if (!(type = pa_classify_guess_stream_node_type(pl))) {
pa_log_debug("cant find stream class for '%s'. "
const char *mnam;
const char *role;
mir_node_type type;
+ mir_node *node;
pa_assert(u);
pa_assert(data);
if (pa_streq(mnam, "module-combine-sink"))
type = mir_node_type_unknown;
else {
- if (pa_streq(mnam, "module-loopback"))
+ if (pa_streq(mnam, "module-loopback")) {
+
+ if (!(node = pa_utils_get_node_from_data(u, mir_input, data))) {
+ pa_log_debug("can't find loopback node for sink-input");
+ return;
+ }
+
+ if (node->direction == mir_output) {
+ pa_log_debug("refuse to preroute loopback sink-input "
+ "(current route: sink %u @ %p)", data->sink ?
+ data->sink->index : PA_IDXSET_INVALID, sink);
+ return;
+ }
+
data->sink = NULL;
+ }
type = pa_classify_guess_stream_node_type(pl);
pa_utils_set_stream_routing_properties(pl, type, data->sink);
}
}
#endif
- if (!pa_sink_input_new_data_set_sink(data, sink, FALSE))
- pa_log("can't set sink %d for new sink-input", sink->index);
+ if (pa_sink_input_new_data_set_sink(data, sink, FALSE))
+ pa_log_debug("set sink %u for new sink-input", sink->index);
+ else
+ pa_log("can't set sink %u for new sink-input", sink->index);
}
}
}
if (!strncmp(media, combine_pattern, sizeof(combine_pattern)-1)) {
pa_log_debug("New stream is a combine stream. Nothing to do ...");
return;
- } else if (!strncmp(media, loopback_pattern, sizeof(loopback_pattern)-1)) {
+ } else if (!strncmp(media, loopback_outpatrn,sizeof(loopback_outpatrn)-1)){
pa_log_debug("New stream is a loopback output stream");
- if ((node = pa_utils_get_node_from_stream(u, sinp))) {
+ if ((node = pa_utils_get_node_from_stream(u, mir_input, sinp))) {
if (node->direction == mir_input)
pa_log_debug("loopback stream node '%s' found", node->amname);
else {
else {
name = pa_utils_get_sink_input_name(sinp);
- pa_log_debug("dealing with new stream '%s'", name);
+ pa_log_debug("dealing with new input stream '%s'", name);
if ((type = get_stream_routing_class(pl)) == mir_node_type_unknown) {
if (!(type = pa_classify_guess_stream_node_type(pl))) {
}
+void pa_discover_register_source_output(struct userdata *u,
+ pa_source_output *sout)
+{
+ pa_core *core;
+ pa_discover *discover;
+ pa_proplist *pl;
+ char *name;
+ const char *media;
+ mir_node_type type;
+ mir_node data;
+ mir_node *node;
+ mir_node *target;
+ char key[256];
+ pa_source *source;
+ const char *role;
+
+ pa_assert(u);
+ pa_assert(sout);
+ pa_assert_se((core = u->core));
+ pa_assert_se((discover = u->discover));
+ pa_assert_se((pl = sout->proplist));
+
+ if ((media = pa_proplist_gets(sout->proplist, PA_PROP_MEDIA_NAME))) {
+ if (!strncmp(media, loopback_inpatrn, sizeof(loopback_inpatrn)-1)) {
+ pa_log_debug("Seems to be a loopback stream. Nothing to do ...");
+ return;
+ }
+ }
+
+ name = pa_utils_get_source_output_name(sout);
+
+ pa_log_debug("registering output stream '%s'", name);
+
+ if (!(type = pa_classify_guess_stream_node_type(pl))) {
+ pa_log_debug("cant find stream class for '%s'. "
+ "Leaving it alone", name);
+ return;
+ }
+
+ pa_utils_set_stream_routing_properties(pl, type, NULL);
+
+ snprintf(key, sizeof(key), "stream_output.%d", sout->index);
+
+ memset(&data, 0, sizeof(data));
+ data.key = key;
+ data.direction = mir_output;
+ data.implement = mir_stream;
+ data.channels = sout->channel_map.channels;
+ data.type = type;
+ data.visible = TRUE;
+ data.available = TRUE;
+ data.amname = name;
+ data.amdescr = (char *)pa_proplist_gets(pl, PA_PROP_MEDIA_NAME);
+ data.amid = AM_ID_INVALID;
+ data.paname = name;
+ data.paidx = sout->index;
+
+ /*
+ * here we can't guess whether the application requested an explicit
+ * route by sepcifying the target source @ stream creation time.
+ *
+ * the brute force solution: we make a default route for this stream
+ * possibly overwiriting the orginal app request :(
+ */
+ role = pa_proplist_gets(sout->proplist, PA_PROP_MEDIA_ROLE);
+ source = make_input_prerouting(u, &data, role, &target);
+
+ node = create_node(u, &data, NULL);
+ pa_assert(node);
+ pa_discover_add_node_to_ptr_hash(u, sout, node);
+
+ if (source && target) {
+ pa_log_debug("move stream to source %u (%s)",
+ source->index, source->name);
+
+ if (pa_source_output_move_to(sout, source, FALSE) < 0)
+ pa_log("failed to route '%s' => '%s'",node->amname,target->amname);
+ else {
+ pa_log_debug("register route '%s' => '%s'",
+ node->amname, target->amname);
+ /* FIXME: and actually do it ... */
+ }
+ }
+}
+
+void pa_discover_preroute_source_output(struct userdata *u,
+ pa_source_output_new_data *data)
+{
+ pa_core *core;
+ pa_module *m;
+ pa_proplist *pl;
+ pa_discover *discover;
+ mir_node fake;
+ pa_source *source;
+ const char *mnam;
+ const char *role;
+ mir_node_type type;
+ mir_node *node;
+
+ pa_assert(u);
+ pa_assert(data);
+ pa_assert_se((core = u->core));
+ pa_assert_se((discover = u->discover));
+ pa_assert_se((pl = data->proplist));
+
+ mnam = (m = data->module) ? m->name : "";
+
+ if (pa_streq(mnam, "module-loopback")) {
+ if (!(node = pa_utils_get_node_from_data(u, mir_output, data))) {
+ pa_log_debug("can't find loopback node for source-output");
+ return;
+ }
+
+ if (node->direction == mir_input) {
+ pa_log_debug("refuse to preroute loopback source-output "
+ "(current route: source %u @ %p)", data->source ?
+ data->source->index : PA_IDXSET_INVALID, source);
+ return;
+ }
+
+ data->source = NULL;
+ }
+ type = pa_classify_guess_stream_node_type(pl);
+ pa_utils_set_stream_routing_properties(pl, type, data->source);
+
+ if (!data->source) {
+ memset(&fake, 0, sizeof(fake));
+ fake.direction = mir_output;
+ fake.implement = mir_stream;
+ fake.channels = data->channel_map.channels;
+ fake.type = type;
+ fake.visible = TRUE;
+ fake.available = TRUE;
+ fake.amname = "<preroute source-output>";
+
+ role = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ROLE);
+ source = make_input_prerouting(u, &fake, role, NULL);
+
+ if (source) {
+ if (pa_source_output_new_data_set_source(data, source, FALSE))
+ pa_log_debug("set source %u for new source-output");
+ else {
+ pa_log("can't set source %u for new source-output",
+ source->index);
+ }
+ }
+ }
+}
+
+
+void pa_discover_add_source_output(struct userdata *u, pa_source_output *sout)
+{
+ pa_core *core;
+ pa_source *s;
+ pa_proplist *pl;
+ pa_discover *discover;
+ mir_node data;
+ mir_node *node;
+ mir_node *snod;
+ char *name;
+ const char *media;
+ mir_node_type type;
+ char key[256];
+ pa_bool_t created;
+
+ pa_assert(u);
+ pa_assert(sout);
+ pa_assert_se((core = u->core));
+ pa_assert_se((discover = u->discover));
+ pa_assert_se((pl = sout->proplist));
+
+ if (!(media = pa_proplist_gets(sout->proplist, PA_PROP_MEDIA_NAME)))
+ media = "<unknown>";
+
+ if (!strncmp(media, loopback_inpatrn, sizeof(loopback_inpatrn)-1)) {
+ pa_log_debug("New stream is a loopback input stream");
+
+ if ((node = pa_utils_get_node_from_stream(u, mir_output, sout))) {
+ if (node->direction == mir_output)
+ pa_log_debug("loopback stream node '%s' found", node->amname);
+ else {
+ pa_log_debug("ignoring it");
+ return;
+ }
+ }
+ else {
+ pa_log_debug("can't find node for the loopback stream");
+ return;
+ }
+ }
+ else {
+ name = pa_utils_get_source_output_name(sout);
+
+ pa_log_debug("dealing with new output stream '%s'", name);
+
+ if ((type = get_stream_routing_class(pl)) == mir_node_type_unknown) {
+ if (!(type = pa_classify_guess_stream_node_type(pl))) {
+ pa_log_debug("cant find stream class for '%s'. "
+ "Leaving it alone", name);
+ return;
+ }
+
+ pa_utils_set_stream_routing_properties(pl, type, NULL);
+
+ /* if needed, make some post-routing here */
+ }
+
+ /* we need to add this to main hashmap as that is used for loop
+ through on all nodes. */
+ snprintf(key, sizeof(key), "stream_output.%d", sout->index);
+
+ memset(&data, 0, sizeof(data));
+ data.key = key;
+ data.direction = mir_output;
+ data.implement = mir_stream;
+ data.channels = sout->channel_map.channels;
+ data.type = type;
+ data.visible = TRUE;
+ data.available = TRUE;
+ data.amname = name;
+ data.amdescr = (char *)pa_proplist_gets(pl, PA_PROP_MEDIA_NAME);
+ data.amid = AM_ID_INVALID;
+ data.paname = name;
+ data.paidx = sout->index;
+
+ node = create_node(u, &data, &created);
+
+ pa_assert(node);
+
+ if (!created) {
+ pa_log("%s: confused with stream. '%s' did exists",
+ __FILE__, node->amname);
+ return;
+ }
+
+ pa_discover_add_node_to_ptr_hash(u, sout, node);
+ }
+
+ if ((s = sout->source))
+ pa_log_debug("routing target candidate is %u (%s)", s->index, s->name);
+
+ if (!s || !(snod = pa_hashmap_get(discover->nodes.byptr, s)))
+ pa_log_debug("can't figure out where this stream is routed");
+ else {
+ pa_log_debug("register route '%s' => '%s'",
+ snod->amname, node->amname);
+ /* FIXME: and actually do it ... */
+
+ }
+}
+
+
+void pa_discover_remove_source_output(struct userdata *u,
+ pa_source_output *sout)
+{
+ pa_discover *discover;
+ mir_node *node;
+ mir_node *srcnod;
+ char *name;
+ pa_loopnode *loop;
+
+ pa_assert(u);
+ pa_assert(sout);
+ pa_assert_se((discover = u->discover));
+
+ name = pa_utils_get_source_output_name(sout);
+
+ pa_log("source-output '%s' going to be destroyed", name);
+
+ if (!(node = pa_discover_remove_node_from_ptr_hash(u, sout)))
+ pa_log_debug("can't find node for source-output (name '%s')", name);
+ else {
+ pa_log_debug("node found for '%s'. After clearing routes "
+ "it will be destroyed", name);
+
+ if (!(srcnod = pa_hashmap_get(discover->nodes.byptr, sout->source)))
+ pa_log_debug("can't figure out where this stream is routed");
+ else {
+ pa_log_debug("clear route '%s' => '%s'",
+ node->amname, srcnod->amname);
+
+ /* FIXME: and actually do it ... */
+
+ }
+
+ destroy_node(u, node);
+
+ mir_router_make_routing(u);
+ }
+}
+
+
mir_node *pa_discover_find_node_by_key(struct userdata *u, const char *key)
{
pa_discover *discover;
snprintf(key, sizeof(key), "%s@%s", paname, prof->name);
pa_classify_node_by_card(&data, card, prof, NULL);
node = create_node(u, &data, NULL);
+#if 0
cd = mir_constrain_create(u, "profile", mir_constrain_profile,
paname);
+#endif
mir_constrain_add_node(u, cd, node);
}
snprintf(key, sizeof(key), "%s@%s", paname, prof->name);
pa_classify_node_by_card(&data, card, prof, NULL);
node = create_node(u, &data, NULL);
+#if 0
+ cd = mir_constrain_create(u, "profile", mir_constrain_profile,
+ paname);
+#endif
mir_constrain_add_node(u, cd, node);
}
}
pa_log("can't route to default '%s': no sink", target->amname);
else {
if (!(sink = pa_idxset_get_by_index(core->sinks, target->paidx)))
- pa_log("can't route to default '%s': sink is gone",target->amname);
+ pa_log("no route to default '%s': sink is gone", target->amname);
else {
if (pa_classify_multiplex_stream(data)) {
data->mux = pa_multiplex_create(u->multiplex, core,
}
+static pa_source *make_input_prerouting(struct userdata *u,
+ mir_node *data,
+ const char *media_role,
+ mir_node **target_ret)
+{
+ pa_core *core;
+ mir_node *target;
+ pa_source *source = NULL;
+
+ pa_assert(u);
+ pa_assert(data);
+ pa_assert_se((core = u->core));
+
+ target = mir_router_make_prerouting(u, data);
+
+ if (!target)
+ pa_log("there is no default route for the stream '%s'", data->amname);
+ else if (target->paidx == PA_IDXSET_INVALID)
+ pa_log("can't route to default '%s': no source", target->amname);
+ else {
+ if (!(source = pa_idxset_get_by_index(core->sources, target->paidx)))
+ pa_log("no route to default '%s': source is gone",target->amname);
+ }
+
+ if (target_ret)
+ *target_ret = target;
+
+ return source;
+}
+
static mir_node_type get_stream_routing_class(pa_proplist *pl)
{
const char *clid;
pa_hook_slot *unlink;
};
+struct pa_source_output_hooks {
+ pa_hook_slot *neew;
+ pa_hook_slot *put;
+ pa_hook_slot *unlink;
+};
+
struct pa_tracker {
- pa_card_hooks card;
- pa_port_hooks port;
- pa_sink_hooks sink;
- pa_source_hooks source;
- pa_sink_input_hooks sink_input;
+ pa_card_hooks card;
+ pa_port_hooks port;
+ pa_sink_hooks sink;
+ pa_source_hooks source;
+ pa_sink_input_hooks sink_input;
+ pa_source_output_hooks source_output;
};
static pa_hook_result_t sink_input_put(void *, void *, void *);
static pa_hook_result_t sink_input_unlink(void *, void *, void *);
+static pa_hook_result_t source_output_new(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 *);
+
pa_tracker *pa_tracker_init(struct userdata *u)
{
- pa_core *core;
- pa_hook *hooks;
- pa_tracker *tracker;
- pa_card_hooks *card;
- pa_port_hooks *port;
- pa_sink_hooks *sink;
- pa_source_hooks *source;
- pa_sink_input_hooks *sinp;
+ pa_core *core;
+ pa_hook *hooks;
+ pa_tracker *tracker;
+ pa_card_hooks *card;
+ pa_port_hooks *port;
+ pa_sink_hooks *sink;
+ pa_source_hooks *source;
+ pa_sink_input_hooks *sinp;
+ pa_source_output_hooks *sout;
pa_assert(u);
pa_assert_se((core = u->core));
sink = &tracker->sink;
source = &tracker->source;
sinp = &tracker->sink_input;
+ sout = &tracker->source_output;
/* card */
card->put = pa_hook_connect(
PA_HOOK_LATE, sink_input_unlink, u
);
+ /* source-output */
+ sout->neew = pa_hook_connect(
+ hooks + PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
+ PA_HOOK_EARLY, source_output_new, u
+ );
+ sout->put = pa_hook_connect(
+ hooks + PA_CORE_HOOK_SOURCE_OUTPUT_PUT,
+ PA_HOOK_LATE, source_output_put, u
+ );
+ sout->unlink = pa_hook_connect(
+ hooks + PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK,
+ PA_HOOK_LATE, source_output_unlink, u
+ );
+
return tracker;
}
void pa_tracker_synchronize(struct userdata *u)
{
- pa_core *core;
- pa_card *card;
- pa_sink *sink;
- pa_source *source;
- pa_sink_input *sinp;
- uint32_t index;
+ pa_core *core;
+ pa_card *card;
+ pa_sink *sink;
+ pa_source *source;
+ pa_sink_input *sinp;
+ pa_source_output *sout;
+ uint32_t index;
pa_assert(u);
pa_assert_se((core = u->core));
pa_discover_add_source(u, source);
}
- /* Hmm... we should first collect all sink-inputs, assign
+ /* Hmm... we should first collect all sink-inputs & source-outputs, assign
priority to them, sort them, and call pa_discover_register_sink_input()
in reverse priority order. Until than we may experience sound leaks
unnecessary profile changes etc ... */
pa_discover_register_sink_input(u, sinp);
}
+ PA_IDXSET_FOREACH(sout, core->source_outputs, index) {
+ pa_discover_register_source_output(u, sout);
+ }
+
mir_router_make_routing(u);
}
}
+static pa_hook_result_t source_output_new(void *hook_data,
+ void *call_data,
+ void *slot_data)
+{
+ pa_source_output_new_data *data = (pa_source_output_new_data *)call_data;
+ struct userdata *u = (struct userdata *)slot_data;
+
+ pa_assert(u);
+ pa_assert(data);
+
+ pa_discover_preroute_source_output(u, data);
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_put(void *hook_data,
+ void *call_data,
+ void *slot_data)
+{
+ pa_source_output *sout = (pa_source_output *)call_data;
+ struct userdata *u = (struct userdata *)slot_data;
+
+ pa_assert(u);
+ pa_assert(sout);
+
+ pa_discover_add_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 = (pa_source_output *)call_data;
+ struct userdata *u = (struct userdata *)slot_data;
+
+ pa_assert(u);
+ pa_assert(sout);
+
+ pa_discover_remove_source_output(u, sout);
+
+ return PA_HOOK_OK;
+}
+
+
/*
* Local Variables:
* c-basic-offset: 4
#include <pulsecore/sink.h>
#include <pulsecore/source.h>
#include <pulsecore/sink-input.h>
+#include <pulsecore/source-output.h>
#include "userdata.h"
#include "utils.h"
static uint32_t stamp;
-static char *sink_input_name(pa_proplist *);
+static char *stream_name(pa_proplist *);
pa_null_sink *pa_utils_create_null_sink(struct userdata *u, const char *name)
{
char *name;
- if (sinp && (name = sink_input_name(sinp->proplist)))
+ if (sinp && (name = stream_name(sinp->proplist)))
return name;
return "<unknown>";
{
char *name;
- if (data && (name = sink_input_name(data->proplist)))
+ if (data && (name = stream_name(data->proplist)))
+ return name;
+
+ return "<unknown>";
+}
+
+
+char *pa_utils_get_source_output_name(pa_source_output *sout)
+{
+ char *name;
+
+ if (sout && (name = stream_name(sout->proplist)))
+ return name;
+
+ return "<unknown>";
+}
+
+char *pa_utils_get_source_output_name_from_data(pa_source_output_new_data*data)
+{
+ char *name;
+
+ if (data && (name = stream_name(data->proplist)))
return name;
return "<unknown>";
void pa_utils_set_stream_routing_properties(pa_proplist *pl,
int styp,
- pa_sink *sink)
+ void *target)
{
const char *clnam;
const char *method;
snprintf(clid, sizeof(clid), "%d", styp);
clnam = mir_node_type_str(styp);
- method = sink ? PA_ROUTING_EXPLICIT : PA_ROUTING_DEFAULT;
+ method = target ? PA_ROUTING_EXPLICIT : PA_ROUTING_DEFAULT;
if (pa_proplist_sets(pl, PA_PROP_ROUTING_CLASS_NAME, clnam ) < 0 ||
pa_proplist_sets(pl, PA_PROP_ROUTING_CLASS_ID , clid ) < 0 ||
pa_proplist_sets(pl, PA_PROP_ROUTING_METHOD , method) < 0 )
{
- pa_log("failed to set some property on sink-input");
+ pa_log("failed to set some stream property");
}
}
return (int)clid;
}
-mir_node *pa_utils_get_node_from_stream(struct userdata *u,pa_sink_input *sinp)
+mir_node *pa_utils_get_node_from_stream(struct userdata *u,
+ mir_direction type,
+ void *ptr)
{
- mir_node *node;
- const char *index_str;
- uint32_t index = PA_IDXSET_INVALID;
- char *e;
+ pa_sink_input *sinp;
+ pa_source_output *sout;
+ pa_proplist *pl;
+ mir_node *node;
+ const char *index_str;
+ uint32_t index = PA_IDXSET_INVALID;
+ char *e;
+ char name[256];
pa_assert(u);
- pa_assert(sinp);
+ pa_assert(ptr);
+ pa_assert(type == mir_input || type == mir_output);
+
+ if (type == mir_input) {
+ sinp = (pa_sink_input *)ptr;
+ pl = sinp->proplist;
+ snprintf(name, sizeof(name), "sink-input.%u", sinp->index);
+ }
+ else {
+ sout = (pa_source_output *)ptr;
+ pl = sout->proplist;
+ snprintf(name, sizeof(name), "source-output.%u", sout->index);
+ }
+
+
+ if ((index_str = pa_proplist_gets(pl, PA_PROP_NODE_INDEX))) {
+ index = strtoul(index_str, &e, 10);
+ if (e != index_str && *e == '\0') {
+ if ((node = mir_node_find_by_index(u, index)))
+ return node;
+
+ pa_log_debug("can't find find node for %s", name);
+ }
+ }
+
+ return NULL;
+}
+
+mir_node *pa_utils_get_node_from_data(struct userdata *u,
+ mir_direction type,
+ void *ptr)
+{
+ pa_sink_input_new_data *sinp;
+ pa_source_output_new_data *sout;
+ pa_proplist *pl;
+ mir_node *node;
+ const char *index_str;
+ uint32_t index = PA_IDXSET_INVALID;
+ char *e;
+ char name[256];
+
+ pa_assert(u);
+ pa_assert(ptr);
+ pa_assert(type == mir_input || type == mir_output);
+
+ if (type == mir_input) {
+ sinp = (pa_sink_input_new_data *)ptr;
+ pl = sinp->proplist;
+ snprintf(name, sizeof(name), "sink-input");
+ }
+ else {
+ sout = (pa_source_output_new_data *)ptr;
+ pl = sout->proplist;
+ snprintf(name, sizeof(name), "source-output");
+ }
+
- if ((index_str = pa_proplist_gets(sinp->proplist, PA_PROP_NODE_INDEX))) {
+ if ((index_str = pa_proplist_gets(pl, PA_PROP_NODE_INDEX))) {
index = strtoul(index_str, &e, 10);
if (e != index_str && *e == '\0') {
if ((node = mir_node_find_by_index(u, index)))
return node;
- pa_log_debug("can't find find node for sink-input.%u",sinp->index);
+ pa_log_debug("can't find find node for %s", name);
}
}
return NULL;
}
-static char *sink_input_name(pa_proplist *pl)
+static char *stream_name(pa_proplist *pl)
{
const char *appnam;
const char *binnam;