[PATCH v5 29/39] bluetooth: Start / stop I/O thread for BlueZ 5 cards

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux Audio Users]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux