diff options
author | Wim Taymans <wtaymans@redhat.com> | 2014-08-08 22:35:12 +0200 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2014-08-08 22:35:12 +0200 |
commit | b3b0d61933e518c583b540c628879e22a179d410 (patch) | |
tree | 9ec6a484450fbb61290e7b64b863d63b61f737b4 | |
parent | 740b9a707bd14b29d974553bd14896752a0ae527 (diff) |
headset: fix cleanup
-rw-r--r-- | src/modules/module-headset.c | 107 |
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), |