[PATCH v5 23/39] bluetooth: Create BlueZ 5 card

[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 | 182 +++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)

diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
index 4bd7f34..1867de9 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -24,6 +24,8 @@
 #include <config.h>
 #endif
 
+#include <pulsecore/core-util.h>
+#include <pulsecore/i18n.h>
 #include <pulsecore/module.h>
 #include <pulsecore/modargs.h>
 
@@ -50,8 +52,182 @@ struct userdata {
 
     pa_bluetooth_discovery *discovery;
     pa_bluetooth_device *device;
+
+    pa_card *card;
+    pa_bluetooth_profile_t profile;
 };
 
+typedef enum pa_bluetooth_form_factor {
+    PA_BLUETOOTH_FORM_FACTOR_UNKNOWN,
+    PA_BLUETOOTH_FORM_FACTOR_HEADSET,
+    PA_BLUETOOTH_FORM_FACTOR_HANDSFREE,
+    PA_BLUETOOTH_FORM_FACTOR_MICROPHONE,
+    PA_BLUETOOTH_FORM_FACTOR_SPEAKER,
+    PA_BLUETOOTH_FORM_FACTOR_HEADPHONE,
+    PA_BLUETOOTH_FORM_FACTOR_PORTABLE,
+    PA_BLUETOOTH_FORM_FACTOR_CAR,
+    PA_BLUETOOTH_FORM_FACTOR_HIFI,
+    PA_BLUETOOTH_FORM_FACTOR_PHONE,
+} pa_bluetooth_form_factor_t;
+
+/* Run from main thread */
+static pa_bluetooth_form_factor_t form_factor_from_class(uint32_t class_of_device) {
+    unsigned major, minor;
+    pa_bluetooth_form_factor_t r;
+
+    static const pa_bluetooth_form_factor_t table[] = {
+        [1] = PA_BLUETOOTH_FORM_FACTOR_HEADSET,
+        [2] = PA_BLUETOOTH_FORM_FACTOR_HANDSFREE,
+        [4] = PA_BLUETOOTH_FORM_FACTOR_MICROPHONE,
+        [5] = PA_BLUETOOTH_FORM_FACTOR_SPEAKER,
+        [6] = PA_BLUETOOTH_FORM_FACTOR_HEADPHONE,
+        [7] = PA_BLUETOOTH_FORM_FACTOR_PORTABLE,
+        [8] = PA_BLUETOOTH_FORM_FACTOR_CAR,
+        [10] = PA_BLUETOOTH_FORM_FACTOR_HIFI
+    };
+
+    /*
+     * See Bluetooth Assigned Numbers:
+     * https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
+     */
+    major = (class_of_device >> 8) & 0x1F;
+    minor = (class_of_device >> 2) & 0x3F;
+
+    switch (major) {
+        case 2:
+            return PA_BLUETOOTH_FORM_FACTOR_PHONE;
+        case 4:
+            break;
+        default:
+            pa_log_debug("Unknown Bluetooth major device class %u", major);
+            return PA_BLUETOOTH_FORM_FACTOR_UNKNOWN;
+    }
+
+    r = minor < PA_ELEMENTSOF(table) ? table[minor] : PA_BLUETOOTH_FORM_FACTOR_UNKNOWN;
+
+    if (!r)
+        pa_log_debug("Unknown Bluetooth minor device class %u", minor);
+
+    return r;
+}
+
+/* Run from main thread */
+static const char *form_factor_to_string(pa_bluetooth_form_factor_t ff) {
+    switch (ff) {
+        case PA_BLUETOOTH_FORM_FACTOR_UNKNOWN:
+            return "unknown";
+        case PA_BLUETOOTH_FORM_FACTOR_HEADSET:
+            return "headset";
+        case PA_BLUETOOTH_FORM_FACTOR_HANDSFREE:
+            return "hands-free";
+        case PA_BLUETOOTH_FORM_FACTOR_MICROPHONE:
+            return "microphone";
+        case PA_BLUETOOTH_FORM_FACTOR_SPEAKER:
+            return "speaker";
+        case PA_BLUETOOTH_FORM_FACTOR_HEADPHONE:
+            return "headphone";
+        case PA_BLUETOOTH_FORM_FACTOR_PORTABLE:
+            return "portable";
+        case PA_BLUETOOTH_FORM_FACTOR_CAR:
+            return "car";
+        case PA_BLUETOOTH_FORM_FACTOR_HIFI:
+            return "hifi";
+        case PA_BLUETOOTH_FORM_FACTOR_PHONE:
+            return "phone";
+    }
+
+    pa_assert_not_reached();
+}
+
+/* Run from main thread */
+static char *cleanup_name(const char *name) {
+    char *t, *s, *d;
+    bool space = false;
+
+    pa_assert(name);
+
+    while ((*name >= 1 && *name <= 32) || *name >= 127)
+        name++;
+
+    t = pa_xstrdup(name);
+
+    for (s = d = t; *s; s++) {
+
+        if (*s <= 32 || *s >= 127 || *s == '_') {
+            space = true;
+            continue;
+        }
+
+        if (space) {
+            *(d++) = ' ';
+            space = false;
+        }
+
+        *(d++) = *s;
+    }
+
+    *d = 0;
+
+    return t;
+}
+
+/* Run from main thread */
+static int add_card(struct userdata *u) {
+    const pa_bluetooth_device *d;
+    pa_card_new_data data;
+    char *alias;
+    pa_bluetooth_form_factor_t ff;
+    pa_card_profile *cp;
+    pa_bluetooth_profile_t *p;
+
+    pa_assert(u);
+    pa_assert(u->device);
+
+    d = u->device;
+
+    pa_card_new_data_init(&data);
+    data.driver = __FILE__;
+    data.module = u->module;
+
+    alias = cleanup_name(d->alias);
+    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, alias);
+    pa_xfree(alias);
+
+    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, d->address);
+    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "bluez");
+    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound");
+    pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "bluetooth");
+
+    if ((ff = form_factor_from_class(d->class_of_device)) != PA_BLUETOOTH_FORM_FACTOR_UNKNOWN)
+        pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, form_factor_to_string(ff));
+
+    pa_proplist_sets(data.proplist, "bluez.path", d->path);
+    pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", d->class_of_device);
+    pa_proplist_sets(data.proplist, "bluez.alias", d->alias);
+    data.name = pa_sprintf_malloc("bluez_card.%s", d->address);
+    data.namereg_fail = false;
+
+    cp = pa_card_profile_new("off", _("Off"), sizeof(pa_bluetooth_profile_t));
+    cp->available = PA_AVAILABLE_YES;
+    p = PA_CARD_PROFILE_DATA(cp);
+    *p = PA_BLUETOOTH_PROFILE_OFF;
+    pa_hashmap_put(data.profiles, cp->name, cp);
+
+    u->card = pa_card_new(u->core, &data);
+    pa_card_new_data_done(&data);
+    if (!u->card) {
+        pa_log("Failed to allocate card.");
+        return -1;
+    }
+
+    u->card->userdata = u;
+
+    p = PA_CARD_PROFILE_DATA(u->card->active_profile);
+    u->profile = *p;
+
+    return 0;
+}
+
 /* Run from main thread */
 static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct userdata *u) {
     pa_assert(d);
@@ -101,6 +277,9 @@ int pa__init(pa_module* m) {
         pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED),
                         PA_HOOK_NORMAL, (pa_hook_cb_t) device_connection_changed_cb, u);
 
+    if (add_card(u) < 0)
+        goto fail;
+
     return 0;
 
 fail:
@@ -124,6 +303,9 @@ void pa__done(pa_module *m) {
     if (u->device_connection_changed_slot)
         pa_hook_slot_free(u->device_connection_changed_slot);
 
+    if (u->card)
+        pa_card_free(u->card);
+
     if (u->discovery)
         pa_bluetooth_discovery_unref(u->discovery);
 
-- 
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