From: Janos Kovacs Date: Tue, 14 Aug 2012 01:34:38 +0000 (+0300) Subject: discovery: add support for stream output (i.e. source-ouput in PA terms) X-Git-Tag: submit/2.0alpha/20121126.141946~13 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8dfd7dbee749276037d0f1c76b663ea1a4ddc69f;p=profile%2Fivi%2Fpulseaudio-module-murphy-ivi.git discovery: add support for stream output (i.e. source-ouput in PA terms) --- diff --git a/murphy/discover.c b/murphy/discover.c index 14f9419..65c5712 100644 --- a/murphy/discover.c +++ b/murphy/discover.c @@ -79,8 +79,9 @@ typedef struct { 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 *); @@ -104,6 +105,8 @@ static char *node_key(struct userdata *, mir_direction, 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 *); @@ -405,6 +408,7 @@ void pa_discover_add_sink(struct userdata *u, pa_sink *sink, pa_bool_t route) 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))) { @@ -476,6 +480,7 @@ void pa_discover_remove_sink(struct userdata *u, pa_sink *sink) 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); @@ -486,7 +491,7 @@ void pa_discover_remove_sink(struct userdata *u, pa_sink *sink) node->available = FALSE; else { if (!u->state.profile) - schedule_deferred_routing(u); + schedule_deferred_routing(u); } } else { @@ -528,6 +533,7 @@ void pa_discover_add_source(struct userdata *u, pa_source *source) 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))) { @@ -579,6 +585,7 @@ void pa_discover_remove_source(struct userdata *u, pa_source *source) pa_discover *discover; mir_node *node; char *name; + mir_node_type type; pa_assert(u); pa_assert(source); @@ -593,6 +600,21 @@ void pa_discover_remove_source(struct userdata *u, pa_source *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"); + } } } @@ -623,7 +645,7 @@ void pa_discover_register_sink_input(struct userdata *u, pa_sink_input *sinp) 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; } @@ -631,7 +653,7 @@ void pa_discover_register_sink_input(struct userdata *u, pa_sink_input *sinp) 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'. " @@ -697,6 +719,7 @@ void pa_discover_preroute_sink_input(struct userdata *u, const char *mnam; const char *role; mir_node_type type; + mir_node *node; pa_assert(u); pa_assert(data); @@ -709,8 +732,22 @@ void pa_discover_preroute_sink_input(struct userdata *u, 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); } @@ -736,8 +773,10 @@ void pa_discover_preroute_sink_input(struct userdata *u, } #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); } } } @@ -771,10 +810,10 @@ void pa_discover_add_sink_input(struct userdata *u, pa_sink_input *sinp) 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 { @@ -792,7 +831,7 @@ void pa_discover_add_sink_input(struct userdata *u, pa_sink_input *sinp) 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))) { @@ -900,6 +939,298 @@ void pa_discover_remove_sink_input(struct userdata *u, pa_sink_input *sinp) } +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 = ""; + + 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 = ""; + + 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; @@ -1048,8 +1379,10 @@ static void handle_bluetooth_card(struct userdata *u, pa_card *card) 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); } @@ -1062,6 +1395,10 @@ static void handle_bluetooth_card(struct userdata *u, pa_card *card) 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); } } @@ -1506,7 +1843,7 @@ static pa_sink *make_output_prerouting(struct userdata *u, 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, @@ -1528,6 +1865,36 @@ static pa_sink *make_output_prerouting(struct userdata *u, } +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; diff --git a/murphy/discover.h b/murphy/discover.h index 6dce2e9..e31462a 100644 --- a/murphy/discover.h +++ b/murphy/discover.h @@ -94,6 +94,12 @@ void pa_discover_preroute_sink_input(struct userdata *, void pa_discover_add_sink_input(struct userdata *, pa_sink_input *); void pa_discover_remove_sink_input(struct userdata *, pa_sink_input *); +void pa_discover_register_source_output(struct userdata *, pa_source_output *); +void pa_discover_preroute_source_output(struct userdata *, + pa_source_output_new_data *); +void pa_discover_add_source_output(struct userdata *, pa_source_output *); +void pa_discover_remove_source_output(struct userdata *, pa_source_output *); + mir_node *pa_discover_find_node_by_key(struct userdata *, const char *); mir_node *pa_discover_find_node_by_ptr(struct userdata *, void *); diff --git a/murphy/router.c b/murphy/router.c index 0e13dde..3dea21b 100644 --- a/murphy/router.c +++ b/murphy/router.c @@ -251,7 +251,7 @@ pa_bool_t mir_router_assign_class_to_rtgroup(struct userdata *u, "router group not found", clnam, direction, rtgrpnam); } - router->classmap.output[class] = rtg; + classmap[class] = rtg; pa_log_debug("class '%s' assigned to %s routing group '%s'", clnam, direction, rtgrpnam); @@ -436,7 +436,6 @@ mir_node *mir_router_make_prerouting(struct userdata *u, mir_node *data) pa_assert(u); pa_assert_se((router = u->router)); pa_assert_se((data->implement == mir_stream)); - pa_assert_se((data->direction == mir_input)); priority = node_priority(u, data); done = FALSE; @@ -552,6 +551,8 @@ pa_bool_t mir_router_phone_accept(struct userdata *u, mir_rtgroup *rtg, class != mir_jack && class != mir_hdmi && class != mir_spdif && + class != mir_bluetooth_source && + class != mir_bluetooth_sink && class != mir_bluetooth_carkit ) { return TRUE; diff --git a/murphy/tracker.c b/murphy/tracker.c index 50d44e8..72d6157 100644 --- a/murphy/tracker.c +++ b/murphy/tracker.c @@ -57,13 +57,20 @@ struct pa_sink_input_hooks { 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; }; @@ -85,17 +92,22 @@ static pa_hook_result_t sink_input_new(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 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)); @@ -107,6 +119,7 @@ pa_tracker *pa_tracker_init(struct userdata *u) sink = &tracker->sink; source = &tracker->source; sinp = &tracker->sink_input; + sout = &tracker->source_output; /* card */ card->put = pa_hook_connect( @@ -166,6 +179,20 @@ pa_tracker *pa_tracker_init(struct userdata *u) 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; } @@ -211,12 +238,13 @@ void pa_tracker_done(struct userdata *u) 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)); @@ -234,7 +262,7 @@ void pa_tracker_synchronize(struct userdata *u) 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 ... */ @@ -243,6 +271,10 @@ void pa_tracker_synchronize(struct userdata *u) 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); } @@ -458,6 +490,53 @@ static pa_hook_result_t sink_input_unlink(void *hook_data, } +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 diff --git a/murphy/userdata.h b/murphy/userdata.h index eab55c8..eb2c78d 100644 --- a/murphy/userdata.h +++ b/murphy/userdata.h @@ -56,6 +56,8 @@ typedef struct pa_port_hooks pa_port_hooks; typedef struct pa_sink_hooks pa_sink_hooks; typedef struct pa_source_hooks pa_source_hooks; typedef struct pa_sink_input_hooks pa_sink_input_hooks; +typedef struct pa_source_output_hooks pa_source_output_hooks; + typedef enum mir_direction mir_direction; typedef enum mir_implement mir_implement; diff --git a/murphy/utils.c b/murphy/utils.c index 5316cf1..b7d3da0 100644 --- a/murphy/utils.c +++ b/murphy/utils.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "userdata.h" #include "utils.h" @@ -57,7 +58,7 @@ struct pa_null_sink { 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) @@ -159,7 +160,7 @@ char *pa_utils_get_sink_input_name(pa_sink_input *sinp) { char *name; - if (sinp && (name = sink_input_name(sinp->proplist))) + if (sinp && (name = stream_name(sinp->proplist))) return name; return ""; @@ -169,7 +170,28 @@ char *pa_utils_get_sink_input_name_from_data(pa_sink_input_new_data *data) { char *name; - if (data && (name = sink_input_name(data->proplist))) + if (data && (name = stream_name(data->proplist))) + return name; + + return ""; +} + + +char *pa_utils_get_source_output_name(pa_source_output *sout) +{ + char *name; + + if (sout && (name = stream_name(sout->proplist))) + return name; + + return ""; +} + +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 ""; @@ -178,7 +200,7 @@ char *pa_utils_get_sink_input_name_from_data(pa_sink_input_new_data *data) void pa_utils_set_stream_routing_properties(pa_proplist *pl, int styp, - pa_sink *sink) + void *target) { const char *clnam; const char *method; @@ -189,13 +211,13 @@ void pa_utils_set_stream_routing_properties(pa_proplist *pl, 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"); } } @@ -243,30 +265,91 @@ int pa_utils_get_stream_class(pa_proplist *pl) 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; diff --git a/murphy/utils.h b/murphy/utils.h index b2fd42d..73a8872 100644 --- a/murphy/utils.h +++ b/murphy/utils.h @@ -35,14 +35,17 @@ char *pa_utils_get_sink_name(pa_sink *); char *pa_utils_get_source_name(pa_source *); char *pa_utils_get_sink_input_name(pa_sink_input *); char *pa_utils_get_sink_input_name_from_data(pa_sink_input_new_data *); +char *pa_utils_get_source_output_name(pa_source_output *); +char *pa_utils_get_source_output_name_from_data(pa_source_output_new_data *); -void pa_utils_set_stream_routing_properties(pa_proplist *, int, pa_sink *); +void pa_utils_set_stream_routing_properties(pa_proplist *, int, void *); void pa_utils_set_stream_routing_method_property(pa_proplist *, pa_bool_t); pa_bool_t pa_utils_stream_has_default_route(pa_proplist *); int pa_utils_get_stream_class(pa_proplist *); #ifdef foouserdatafoo /* argh ... */ -mir_node *pa_utils_get_node_from_stream(struct userdata *, pa_sink_input *); +mir_node *pa_utils_get_node_from_stream(struct userdata *,mir_direction,void*); +mir_node *pa_utils_get_node_from_data(struct userdata *, mir_direction,void *); #endif const char *pa_utils_file_path(const char *, char *, size_t);