summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pa-sink-ctl.c212
-rw-r--r--src/pa-sink-ctl.h4
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;
};