From ae606015e27940ae310fd864095d3f8121844205 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Fri, 21 Oct 2011 14:12:45 +0200 Subject: Make use of gradual updates ..to stop retreiving all sinks and inputs on every small change. --- src/pa-sink-ctl.c | 212 +++++++++++++++++++++++++++++++----------------------- src/pa-sink-ctl.h | 4 -- 2 files changed, 123 insertions(+), 93 deletions(-) diff --git a/src/pa-sink-ctl.c b/src/pa-sink-ctl.c index 8408c3e..e0f91c7 100644 --- a/src/pa-sink-ctl.c +++ b/src/pa-sink-ctl.c @@ -12,64 +12,32 @@ g_memdup(&(data), sizeof(data))); \ } while (0) -static void -collect_all_info(struct context *ctx); - -static void -subscribe_cb(pa_context *c, pa_subscription_event_type_t t, guint32 idx, gpointer userdata) +static sink_input_info * +find_sink_input_by_idx(struct context *ctx, gint idx) { - struct context *ctx = userdata; + GList *l; - if (!ctx->info_callbacks_finished) - ctx->info_callbacks_blocked = TRUE; - else - collect_all_info(ctx); + for (l = ctx->input_list; l; l = l->next) { + sink_input_info *input = l->data; + if (input->index == idx) + return input; + } + + return NULL; } -/* - * is called after connection - */ -static void -context_state_callback(pa_context *c, gpointer userdata) +static sink_info * +find_sink_by_idx(struct context *ctx, gint idx) { - struct context *ctx = userdata; - - ctx->context_ready = FALSE; - switch (pa_context_get_state(c)) { - case PA_CONTEXT_CONNECTING: - interface_set_status(ctx, "connecting..."); - break; - case PA_CONTEXT_AUTHORIZING: - interface_set_status(ctx, "authorizing..."); - break; - case PA_CONTEXT_SETTING_NAME: - interface_set_status(ctx, "setting name..."); - break; + GList *l; - case PA_CONTEXT_READY: - collect_all_info(ctx); - pa_context_set_subscribe_callback(c, subscribe_cb, ctx); - pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SINK_INPUT; - g_assert((ctx->op = pa_context_subscribe(c, (pa_subscription_mask_t) (mask), NULL, NULL))); - ctx->context_ready = TRUE; - interface_set_status(ctx, "ready to process events."); - break; - case PA_CONTEXT_FAILED: - interface_set_status(ctx, "cannot connect!"); - break; - - case PA_CONTEXT_TERMINATED: - g_assert(ctx->op != NULL); - pa_operation_cancel(ctx->op); - pa_operation_unref(ctx->op); - ctx->op = NULL; - interface_set_status(ctx, "connection terminated."); - g_main_loop_quit(ctx->loop); - break; - default: - interface_set_status(ctx, "unknown state"); - break; + for (l = ctx->sink_list; l; l = l->next) { + sink_info *sink = l->data; + if (sink->index == idx) + return sink; } + + return NULL; } /* @@ -87,17 +55,7 @@ get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, gint is } if (is_last) { - g_list_free_full(ctx->input_list, g_free); - ctx->input_list = ctx->tmp_inputs; - - if (++ctx->info_callbacks_finished == 2) { - print_sink_list(ctx); - - if (ctx->info_callbacks_blocked) { - ctx->info_callbacks_blocked = FALSE; - collect_all_info(ctx); - } - } + print_sink_list(ctx); return; } @@ -115,7 +73,11 @@ get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, gint is .pid = NULL /* maybe obsolete */ }; - list_append_struct(ctx->tmp_inputs, sink_input); + sink_input_info *inlist = find_sink_input_by_idx(ctx, i->index); + if (inlist) + *inlist = sink_input; + else + list_append_struct(ctx->input_list, sink_input); } /* @@ -133,17 +95,7 @@ get_sink_info_callback(pa_context *c, const pa_sink_info *i, gint is_last, gpoin } if (is_last) { - g_list_free_full(ctx->sink_list, g_free); - ctx->sink_list = ctx->tmp_sinks; - - if (++ctx->info_callbacks_finished == 2) { - print_sink_list(ctx); - if (ctx->info_callbacks_blocked) { - ctx->info_callbacks_blocked = FALSE; - collect_all_info(ctx); - } - } - + print_sink_list(ctx); return; } @@ -157,7 +109,102 @@ get_sink_info_callback(pa_context *c, const pa_sink_info *i, gint is_last, gpoin g_strdup(pa_proplist_gets(i->proplist, "device.product.name")) : NULL, }; - list_append_struct(ctx->tmp_sinks, sink); + sink_info *inlist = find_sink_by_idx(ctx, i->index); + if (inlist) + *inlist = sink; + else + list_append_struct(ctx->sink_list, sink); +} + +static void +subscribe_cb(pa_context *c, pa_subscription_event_type_t t, guint32 idx, gpointer userdata) +{ + struct context *ctx = userdata; + pa_operation *op; + gpointer object; + + switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { + case PA_SUBSCRIPTION_EVENT_NEW: + case PA_SUBSCRIPTION_EVENT_CHANGE: + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + op = pa_context_get_sink_info_by_index(c, idx, get_sink_info_callback, ctx); + pa_operation_unref(op); + break; + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + op = pa_context_get_sink_input_info(c, idx, get_sink_input_info_callback, ctx); + pa_operation_unref(op); + break; + } + break; + case PA_SUBSCRIPTION_EVENT_REMOVE: + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + object = find_sink_by_idx(ctx, idx); + ctx->sink_list = g_list_remove(ctx->sink_list, object); + g_free(object); + break; + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + object = find_sink_input_by_idx(ctx, idx); + ctx->input_list = g_list_remove(ctx->input_list, object); + g_free(object); + break; + default: + return; + } + print_sink_list(ctx); + break; + default: + break; + } +} + +/* + * is called after connection + */ +static void +context_state_callback(pa_context *c, gpointer userdata) +{ + struct context *ctx = userdata; + + ctx->context_ready = FALSE; + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + interface_set_status(ctx, "connecting..."); + break; + case PA_CONTEXT_AUTHORIZING: + interface_set_status(ctx, "authorizing..."); + break; + case PA_CONTEXT_SETTING_NAME: + interface_set_status(ctx, "setting name..."); + break; + + case PA_CONTEXT_READY: + pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, ctx)); + pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, ctx)); + + pa_context_set_subscribe_callback(c, subscribe_cb, ctx); + pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SINK_INPUT; + g_assert((ctx->op = pa_context_subscribe(c, mask, NULL, NULL))); + ctx->context_ready = TRUE; + interface_set_status(ctx, "ready to process events."); + break; + case PA_CONTEXT_FAILED: + interface_set_status(ctx, "cannot connect!"); + break; + + case PA_CONTEXT_TERMINATED: + g_assert(ctx->op != NULL); + pa_operation_cancel(ctx->op); + pa_operation_unref(ctx->op); + ctx->op = NULL; + interface_set_status(ctx, "connection terminated."); + g_main_loop_quit(ctx->loop); + break; + default: + interface_set_status(ctx, "unknown state"); + break; + } } void @@ -178,18 +225,6 @@ change_callback(pa_context* c, gint success, gpointer userdata) return; } -static void -collect_all_info(struct context *ctx) -{ - if (ctx->info_callbacks_finished < 2) - return; - ctx->info_callbacks_finished = 0; - ctx->tmp_sinks = NULL; - ctx->tmp_inputs = NULL; - pa_operation_unref(pa_context_get_sink_info_list(ctx->context, get_sink_info_callback, ctx)); - pa_operation_unref(pa_context_get_sink_input_info_list(ctx->context, get_sink_input_info_callback, ctx)); -} - int main(int argc, char** argv) { @@ -197,9 +232,8 @@ main(int argc, char** argv) pa_mainloop_api *mainloop_api = NULL; pa_glib_mainloop *m = NULL; - ctx->info_callbacks_finished = 2; - ctx->info_callbacks_blocked = FALSE; ctx->sink_list = NULL; + ctx->input_list = NULL; ctx->max_name_len = 0; ctx->context_ready = FALSE; diff --git a/src/pa-sink-ctl.h b/src/pa-sink-ctl.h index 172bfcd..699c21e 100644 --- a/src/pa-sink-ctl.h +++ b/src/pa-sink-ctl.h @@ -25,14 +25,10 @@ struct context { guint max_name_len; - int info_callbacks_finished; - gboolean info_callbacks_blocked; GMainLoop *loop; GList *sink_list; GList *input_list; - GList *tmp_sinks; - GList *tmp_inputs; gchar *status; }; -- cgit