summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2014-08-08 22:35:12 +0200
committerWim Taymans <wtaymans@redhat.com>2014-08-08 22:35:12 +0200
commitb3b0d61933e518c583b540c628879e22a179d410 (patch)
tree9ec6a484450fbb61290e7b64b863d63b61f737b4
parent740b9a707bd14b29d974553bd14896752a0ae527 (diff)
headset: fix cleanup
-rw-r--r--src/modules/module-headset.c107
1 files changed, 89 insertions, 18 deletions
diff --git a/src/modules/module-headset.c b/src/modules/module-headset.c
index 16fee5b5b..c40188b30 100644
--- a/src/modules/module-headset.c
+++ b/src/modules/module-headset.c
@@ -60,6 +60,22 @@ static const char* const valid_modargs[] = {
NULL
};
+typedef struct pa_headset pa_headset;
+
+enum {
+ HEADSET_MESSAGE_IO_THREAD_FAILED,
+ HEADSET_MESSAGE_STREAM_FD_HUP,
+ HEADSET_MESSAGE_MAX
+};
+
+typedef struct headset_msg {
+ pa_msgobject parent;
+ pa_headset *headset;
+} headset_msg;
+PA_DEFINE_PRIVATE_CLASS(headset_msg, pa_msgobject);
+#define HEADSET_MSG(o) (headset_msg_cast(o))
+
+
struct userdata {
pa_module *module;
pa_core *core;
@@ -69,10 +85,11 @@ struct userdata {
pa_hashmap *devices;
};
-typedef struct pa_headset {
+struct pa_headset {
struct userdata *userdata;
char *path;
+ headset_msg *msg;
pa_card *card;
pa_sink *sink;
pa_source *source;
@@ -96,7 +113,7 @@ typedef struct pa_headset {
pa_smoother *read_smoother;
pa_memchunk write_memchunk;
int stream_write_type;
-} pa_headset;
+};
#define MAX_PLAYBACK_CATCH_UP_USEC (100 * PA_USEC_PER_MSEC)
#define FIXED_LATENCY_PLAYBACK (25 * PA_USEC_PER_MSEC)
@@ -693,6 +710,7 @@ static void thread_func(void *userdata) {
do_write = 0;
pending_read_bytes = 0;
writable = false;
+ pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(h->msg), HEADSET_MESSAGE_STREAM_FD_HUP, NULL, 0, NULL, NULL);
} else
goto fail;
}
@@ -829,6 +847,7 @@ static void thread_func(void *userdata) {
fail:
/* If this was no regular exit from the loop we have to continue processing messages until we receive PA_MESSAGE_SHUTDOWN */
pa_log_debug("IO thread failed");
+ pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(h->msg), HEADSET_MESSAGE_IO_THREAD_FAILED, NULL, 0, NULL, NULL);
pa_asyncmsgq_wait_for(h->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
finish:
@@ -926,7 +945,43 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
return 0;
}
-static void add_device(struct userdata *u, const char *path, DBusMessageIter *props) {
+/* Run from main thread context */
+static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+ struct headset_msg *m = HEADSET_MSG(obj);
+ pa_headset *h = m->headset;
+ struct userdata *u = h->userdata;
+
+ switch (code) {
+ case HEADSET_MESSAGE_IO_THREAD_FAILED:
+ if (u->module->unload_requested)
+ break;
+
+ pa_log_debug("Switching the profile to off due to IO thread failure.");
+ pa_assert_se(pa_card_set_profile(h->card, pa_hashmap_get(h->card->profiles, "off"), false) >= 0);
+ break;
+ case HEADSET_MESSAGE_STREAM_FD_HUP:
+ break;
+ }
+
+ return 0;
+}
+
+static void free_headset (pa_headset *h) {
+ pa_assert(h);
+
+ stop_thread(h);
+
+ if (h->card)
+ pa_card_free(h->card);
+
+ if (h->msg)
+ pa_xfree(h->msg);
+
+ pa_xfree(h->path);
+ pa_xfree(h);
+}
+
+static pa_headset * new_headset (struct userdata *u, const char *path, DBusMessageIter *props) {
pa_headset *h;
pa_card_new_data data;
pa_card_profile *p;
@@ -959,35 +1014,55 @@ static void add_device(struct userdata *u, const char *path, DBusMessageIter *pr
/* create the card object */
h->card = pa_card_new(u->core, &data);
+ pa_card_new_data_done(&data);
+
if (!h->card) {
pa_log("Unable to create card.\n");
- return;
+ goto fail;
}
- pa_card_new_data_done(&data);
h->card->userdata = h;
h->card->set_profile = card_set_profile;
+ if (!(h->msg = pa_msgobject_new(headset_msg)))
+ goto fail;
+
+ h->msg->parent.process_msg = device_process_msg;
+
if (headset_connect(h) < 0) {
pa_log("Unable to connect\n");
- return;
+ goto fail;
}
if (add_sink(h) < 0) {
pa_log("Unable to add sink\n");
- return;
+ goto fail;
}
if (add_source(h) < 0) {
pa_log("Unable to add source\n");
- return;
+ goto fail;
}
if (start_thread(h) < 0) {
pa_log("Unable to start thread\n");
- return;
+ goto fail;
}
+ return h;
+
+fail:
+ free_headset (h);
+ return NULL;
+}
+
+static void add_device(struct userdata *u, const char *path, DBusMessageIter *props) {
+ pa_headset *h;
+
+ pa_log_debug("Add device %s", path);
+
+ h = new_headset (u, path, props);
+
pa_assert_se(pa_hashmap_put(u->devices, h->path, h) >= 0);
}
@@ -1000,14 +1075,7 @@ static void remove_device(struct userdata *u, const char *path) {
pa_log_error("Asked to remove unknown device %s", path);
return;
}
-
- stop_thread(h);
-
- if (h->card)
- pa_card_free(h->card);
-
- pa_xfree(h->path);
- pa_xfree(h);
+ free_headset (h);
}
static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
@@ -1134,7 +1202,7 @@ int pa__init(pa_module*m) {
u->core = m->core;
u->module = m;
u->connection = connection;
- u->devices = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, NULL);
+ u->devices = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) free_headset);
if (!dbus_connection_add_filter(pa_dbus_connection_get(connection), filter_cb, u, NULL)) {
pa_log_error("Failed to add filter function");
@@ -1176,6 +1244,9 @@ void pa__done(pa_module *m) {
if (!(u = m->userdata))
return;
+ if (u->devices)
+ pa_hashmap_free(u->devices);
+
if (u->connection) {
pa_dbus_remove_matches(
pa_dbus_connection_get(u->connection),