From: Jo?o Paulo Rechi Vita <jprvita@xxxxxxxxxxxxx> --- src/modules/bluetooth/module-bluez5-device.c | 129 +++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 237f897..3bf9a35 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -30,6 +30,10 @@ #include <pulsecore/i18n.h> #include <pulsecore/module.h> #include <pulsecore/modargs.h> +#include <pulsecore/poll.h> +#include <pulsecore/rtpoll.h> +#include <pulsecore/thread.h> +#include <pulsecore/thread-mq.h> #include "a2dp-codecs.h" #include "bluez5-util.h" @@ -77,6 +81,11 @@ struct userdata { char *output_port_name; char *input_port_name; + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + pa_rtpoll_item *rtpoll_item; + int stream_fd; size_t read_link_mtu; size_t write_link_mtu; @@ -187,6 +196,20 @@ static void connect_ports(struct userdata *u, void *new_data, pa_direction_t dir } } +static void teardown_stream(struct userdata *u) { + if (u->rtpoll_item) { + pa_rtpoll_item_free(u->rtpoll_item); + u->rtpoll_item = NULL; + } + + if (u->stream_fd >= 0) { + pa_close(u->stream_fd); + u->stream_fd = -1; + } + + pa_log_debug("Audio stream torn down"); +} + static int transport_acquire(struct userdata *u, bool optional) { pa_assert(u->transport); @@ -205,6 +228,22 @@ static int transport_acquire(struct userdata *u, bool optional) { return 0; } +static void transport_release(struct userdata *u) { + pa_assert(u->transport); + + /* Ignore if already released */ + if (!u->transport_acquired) + return; + + pa_log_debug("Releasing transport %s", u->transport->path); + + u->transport->release(u->transport); + + u->transport_acquired = false; + + teardown_stream(u); +} + /* Run from main thread */ static int add_source(struct userdata *u) { pa_source_new_data data; @@ -442,6 +481,89 @@ static int init_profile(struct userdata *u) { return r; } +/* I/O thread function */ +static void thread_func(void *userdata) { +} + +/* Run from main thread */ +static int start_thread(struct userdata *u) { + pa_assert(u); + pa_assert(!u->thread); + pa_assert(!u->rtpoll); + pa_assert(!u->rtpoll_item); + + u->rtpoll = pa_rtpoll_new(); + pa_thread_mq_init(&u->thread_mq, u->core->mainloop, u->rtpoll); + + if (!(u->thread = pa_thread_new("bluetooth", thread_func, u))) { + pa_log_error("Failed to create IO thread"); + return -1; + } + + if (u->sink) { + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + pa_sink_put(u->sink); + + if (u->sink->set_volume) + u->sink->set_volume(u->sink); + } + + if (u->source) { + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + pa_source_put(u->source); + + if (u->source->set_volume) + u->source->set_volume(u->source); + } + + return 0; +} + +/* Run from main thread */ +static void stop_thread(struct userdata *u) { + pa_assert(u); + + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->source) + pa_source_unlink(u->source); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + u->thread = NULL; + } + + if (u->rtpoll_item) { + pa_rtpoll_item_free(u->rtpoll_item); + u->rtpoll_item = NULL; + } + + if (u->rtpoll) { + pa_thread_mq_done(&u->thread_mq); + pa_rtpoll_free(u->rtpoll); + u->rtpoll = NULL; + } + + if (u->transport) { + transport_release(u); + u->transport = NULL; + } + + if (u->sink) { + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->source) { + pa_source_unref(u->source); + u->source = NULL; + } +} + /* Run from main thread */ static char *cleanup_name(const char *name) { char *t, *s, *d; @@ -799,9 +921,14 @@ int pa__init(pa_module* m) { if (init_profile(u) < 0) goto off; + if (u->sink || u->source) + if (start_thread(u) < 0) + goto off; + return 0; off: + stop_thread(u); pa_assert_se(pa_card_set_profile(u->card, "off", false) >= 0); @@ -825,6 +952,8 @@ void pa__done(pa_module *m) { if (!(u = m->userdata)) return; + stop_thread(u); + if (u->device_connection_changed_slot) pa_hook_slot_free(u->device_connection_changed_slot); -- 1.8.3.1