[pulseaudio-discuss] [PATCHv2 46/60] bluetooth: Create BlueZ 5 card
jprvita at gmail.com
jprvita at gmail.com
Mon Aug 12 21:54:24 PDT 2013
From: João Paulo Rechi Vita <jprvita at openbossa.org>
---
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 e842b30..695e210 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>
@@ -51,8 +53,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) {
+ 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 >> 8) & 0x1F;
+ minor = (class >> 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->remote);
+ 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", (unsigned) d->class_of_device);
+ pa_proplist_sets(data.proplist, "bluez.alias", d->alias);
+ data.name = pa_sprintf_malloc("bluez_card.%s", d->remote);
+ 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 = 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:
@@ -121,6 +300,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->modargs)
pa_modargs_free(u->modargs);
--
1.7.11.7
More information about the pulseaudio-discuss
mailing list