mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-06 13:29:56 -05:00
bluetooth: Create BlueZ 5 card
This commit is contained in:
parent
6ba1610b6f
commit
501f5e2898
1 changed files with 182 additions and 0 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue