mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
rework device discovery to share a single device list among all modules
This commit is contained in:
parent
20488fbe3e
commit
3aa39726db
4 changed files with 195 additions and 233 deletions
|
|
@ -24,31 +24,19 @@
|
|||
#endif
|
||||
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/shared.h>
|
||||
#include <modules/dbus-util.h>
|
||||
|
||||
#include "bluetooth-util.h"
|
||||
|
||||
enum mode {
|
||||
MODE_FIND,
|
||||
MODE_GET,
|
||||
MODE_DISCOVER
|
||||
};
|
||||
|
||||
struct pa_bluetooth_discovery {
|
||||
DBusConnection *connection;
|
||||
PA_REFCNT_DECLARE;
|
||||
|
||||
pa_core *core;
|
||||
pa_dbus_connection *connection;
|
||||
PA_LLIST_HEAD(pa_dbus_pending, pending);
|
||||
|
||||
enum mode mode;
|
||||
|
||||
/* If mode == MODE_FIND look for a specific device by its address.
|
||||
If mode == MODE_GET look for a specific device by its path. */
|
||||
const char *looking_for;
|
||||
pa_bluetooth_device *found_device;
|
||||
|
||||
/* If looking_for is NULL we do long-time discovery */
|
||||
pa_hashmap *devices;
|
||||
pa_bluetooth_device_callback_t callback;
|
||||
struct userdata *userdata;
|
||||
pa_hook hook;
|
||||
};
|
||||
|
||||
static pa_bluetooth_uuid *uuid_new(const char *uuid) {
|
||||
|
|
@ -73,9 +61,9 @@ static pa_bluetooth_device* device_new(const char *path) {
|
|||
|
||||
d = pa_xnew(pa_bluetooth_device, 1);
|
||||
|
||||
d->device_info_valid = d->audio_sink_info_valid = d->headset_info_valid = 0;
|
||||
d->dead = FALSE;
|
||||
|
||||
d->data = NULL;
|
||||
d->device_info_valid = d->audio_sink_info_valid = d->headset_info_valid = 0;
|
||||
|
||||
d->name = NULL;
|
||||
d->path = pa_xstrdup(path);
|
||||
|
|
@ -94,7 +82,7 @@ static pa_bluetooth_device* device_new(const char *path) {
|
|||
return d;
|
||||
}
|
||||
|
||||
void pa_bluetooth_device_free(pa_bluetooth_device *d) {
|
||||
static void device_free(pa_bluetooth_device *d) {
|
||||
pa_bluetooth_uuid *u;
|
||||
|
||||
pa_assert(d);
|
||||
|
|
@ -127,7 +115,8 @@ static pa_bool_t device_is_audio(pa_bluetooth_device *d) {
|
|||
pa_assert(d->audio_sink_info_valid);
|
||||
pa_assert(d->headset_info_valid);
|
||||
|
||||
return d->device_info_valid > 0 &&
|
||||
return
|
||||
d->device_info_valid > 0 &&
|
||||
(d->audio_sink_info_valid > 0 || d->headset_info_valid > 0);
|
||||
}
|
||||
|
||||
|
|
@ -289,20 +278,18 @@ static int parse_audio_property(pa_bluetooth_discovery *u, int *connected, DBusM
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void run_callback(pa_bluetooth_discovery *y, pa_bluetooth_device *d, pa_bool_t good) {
|
||||
static void run_callback(pa_bluetooth_discovery *y, pa_bluetooth_device *d, pa_bool_t dead) {
|
||||
pa_assert(y);
|
||||
pa_assert(d);
|
||||
|
||||
if (y->mode != MODE_DISCOVER)
|
||||
return;
|
||||
|
||||
if (!device_is_loaded(d))
|
||||
return;
|
||||
|
||||
if (!device_is_audio(d))
|
||||
return;
|
||||
|
||||
y->callback(y->userdata, d, good);
|
||||
d->dead = dead;
|
||||
pa_hook_fire(&y->hook, d);
|
||||
}
|
||||
|
||||
static void get_properties_reply(DBusPendingCall *pending, void *userdata) {
|
||||
|
|
@ -377,7 +364,7 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) {
|
|||
}
|
||||
|
||||
finish:
|
||||
run_callback(y, d, TRUE);
|
||||
run_callback(y, d, FALSE);
|
||||
|
||||
dbus_message_unref(r);
|
||||
|
||||
|
|
@ -392,9 +379,9 @@ static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, pa_bl
|
|||
pa_assert(y);
|
||||
pa_assert(m);
|
||||
|
||||
pa_assert_se(dbus_connection_send_with_reply(y->connection, m, &call, -1));
|
||||
pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(y->connection), m, &call, -1));
|
||||
|
||||
p = pa_dbus_pending_new(y->connection, m, call, y, d);
|
||||
p = pa_dbus_pending_new(pa_dbus_connection_get(y->connection), m, call, y, d);
|
||||
PA_LLIST_PREPEND(pa_dbus_pending, y->pending, p);
|
||||
dbus_pending_call_set_notify(call, func, p, NULL);
|
||||
|
||||
|
|
@ -410,13 +397,7 @@ static void found_device(pa_bluetooth_discovery *y, const char* path) {
|
|||
|
||||
d = device_new(path);
|
||||
|
||||
if (y->mode == MODE_DISCOVER) {
|
||||
pa_assert(y->devices);
|
||||
pa_hashmap_put(y->devices, d->path, d);
|
||||
} else {
|
||||
pa_assert(!y->found_device);
|
||||
y->found_device = d;
|
||||
}
|
||||
pa_hashmap_put(y->devices, d->path, d);
|
||||
|
||||
pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Device", "GetProperties"));
|
||||
send_and_add_to_pending(y, d, m, get_properties_reply);
|
||||
|
|
@ -469,57 +450,11 @@ end:
|
|||
pa_dbus_pending_free(p);
|
||||
}
|
||||
|
||||
static void find_device_reply(DBusPendingCall *pending, void *userdata) {
|
||||
DBusError e;
|
||||
DBusMessage *r;
|
||||
char *path = NULL;
|
||||
pa_dbus_pending *p;
|
||||
pa_bluetooth_discovery *y;
|
||||
|
||||
pa_assert(pending);
|
||||
|
||||
dbus_error_init(&e);
|
||||
|
||||
pa_assert_se(p = userdata);
|
||||
pa_assert_se(y = p->context_data);
|
||||
pa_assert_se(r = dbus_pending_call_steal_reply(pending));
|
||||
|
||||
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
|
||||
pa_log("Error from FindDevice reply: %s", dbus_message_get_error_name(r));
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!dbus_message_get_args(r, &e, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
|
||||
pa_log("org.bluez.Adapter.FindDevice returned an error: '%s'\n", e.message);
|
||||
dbus_error_free(&e);
|
||||
} else
|
||||
found_device(y, path);
|
||||
|
||||
end:
|
||||
dbus_message_unref(r);
|
||||
|
||||
PA_LLIST_REMOVE(pa_dbus_pending, y->pending, p);
|
||||
pa_dbus_pending_free(p);
|
||||
}
|
||||
|
||||
static void found_adapter(pa_bluetooth_discovery *y, const char *path) {
|
||||
DBusMessage *m;
|
||||
|
||||
if (y->mode == MODE_FIND) {
|
||||
pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "FindDevice"));
|
||||
|
||||
pa_assert_se(dbus_message_append_args(m,
|
||||
DBUS_TYPE_STRING, &y->looking_for,
|
||||
DBUS_TYPE_INVALID));
|
||||
|
||||
send_and_add_to_pending(y, NULL, m, find_device_reply);
|
||||
|
||||
} else {
|
||||
pa_assert(y->mode == MODE_DISCOVER);
|
||||
|
||||
pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "ListDevices"));
|
||||
send_and_add_to_pending(y, NULL, m, list_devices_reply);
|
||||
}
|
||||
pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "ListDevices"));
|
||||
send_and_add_to_pending(y, NULL, m, list_devices_reply);
|
||||
}
|
||||
|
||||
static void list_adapters_reply(DBusPendingCall *pending, void *userdata) {
|
||||
|
|
@ -599,11 +534,8 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
|
|||
pa_log_debug("Device %s removed", path);
|
||||
|
||||
if ((d = pa_hashmap_remove(y->devices, path))) {
|
||||
|
||||
pa_assert_se(y->mode == MODE_DISCOVER);
|
||||
run_callback(y, d, FALSE);
|
||||
|
||||
pa_bluetooth_device_free(d);
|
||||
run_callback(y, d, TRUE);
|
||||
device_free(d);
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
|
@ -661,8 +593,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
|
|||
goto fail;
|
||||
}
|
||||
|
||||
pa_assert_se(y->mode == MODE_DISCOVER);
|
||||
run_callback(y, d, TRUE);
|
||||
run_callback(y, d, FALSE);
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
|
@ -674,82 +605,81 @@ fail:
|
|||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
pa_bluetooth_device* pa_bluetooth_find_device(DBusConnection *c, const char* address) {
|
||||
pa_bluetooth_discovery y;
|
||||
const pa_bluetooth_device* pa_bluetooth_discovery_get_by_address(pa_bluetooth_discovery *y, const char* address) {
|
||||
pa_bluetooth_device *d;
|
||||
void *state = NULL;
|
||||
|
||||
memset(&y, 0, sizeof(y));
|
||||
y.mode = MODE_FIND;
|
||||
y.looking_for = address;
|
||||
y.connection = c;
|
||||
PA_LLIST_HEAD_INIT(pa_dbus_pending, y.pending);
|
||||
pa_assert(y);
|
||||
pa_assert(PA_REFCNT_VALUE(y) > 0);
|
||||
pa_assert(address);
|
||||
|
||||
list_adapters(&y);
|
||||
if (!pa_hook_is_firing(&y->hook))
|
||||
pa_bluetooth_discovery_sync(y);
|
||||
|
||||
pa_dbus_sync_pending_list(&y.pending);
|
||||
pa_assert(!y.pending);
|
||||
while ((d = pa_hashmap_iterate(y->devices, &state, NULL)))
|
||||
if (pa_streq(d->address, address))
|
||||
return d;
|
||||
|
||||
if (y.found_device) {
|
||||
pa_assert(device_is_loaded(y.found_device));
|
||||
|
||||
if (!device_is_audio(y.found_device)) {
|
||||
pa_bluetooth_device_free(y.found_device);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return y.found_device;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pa_bluetooth_device* pa_bluetooth_get_device(DBusConnection *c, const char* path) {
|
||||
pa_bluetooth_discovery y;
|
||||
const pa_bluetooth_device* pa_bluetooth_discovery_get_by_path(pa_bluetooth_discovery *y, const char* path) {
|
||||
pa_assert(y);
|
||||
pa_assert(PA_REFCNT_VALUE(y) > 0);
|
||||
pa_assert(path);
|
||||
|
||||
memset(&y, 0, sizeof(y));
|
||||
y.mode = MODE_GET;
|
||||
y.connection = c;
|
||||
PA_LLIST_HEAD_INIT(pa_dbus_pending, y.pending);
|
||||
if (!pa_hook_is_firing(&y->hook))
|
||||
pa_bluetooth_discovery_sync(y);
|
||||
|
||||
found_device(&y, path);
|
||||
|
||||
pa_dbus_sync_pending_list(&y.pending);
|
||||
pa_assert(!y.pending);
|
||||
|
||||
if (y.found_device) {
|
||||
pa_assert(device_is_loaded(y.found_device));
|
||||
|
||||
if (!device_is_audio(y.found_device)) {
|
||||
pa_bluetooth_device_free(y.found_device);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return y.found_device;
|
||||
return pa_hashmap_get(y->devices, path);
|
||||
}
|
||||
|
||||
pa_bluetooth_discovery* pa_bluetooth_discovery_new(DBusConnection *c, pa_bluetooth_device_callback_t cb, struct userdata *u) {
|
||||
static int setup_dbus(pa_bluetooth_discovery *y) {
|
||||
DBusError err;
|
||||
|
||||
dbus_error_init(&err);
|
||||
|
||||
y->connection = pa_dbus_bus_get(y->core, DBUS_BUS_SYSTEM, &err);
|
||||
|
||||
if (dbus_error_is_set(&err) || !y->connection) {
|
||||
pa_log("Failed to get D-Bus connection: %s", err.message);
|
||||
dbus_error_free(&err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
|
||||
DBusError err;
|
||||
pa_bluetooth_discovery *y;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(cb);
|
||||
|
||||
dbus_error_init(&err);
|
||||
|
||||
if ((y = pa_shared_get(c, "bluetooth-discovery")))
|
||||
return pa_bluetooth_discovery_ref(y);
|
||||
|
||||
y = pa_xnew0(pa_bluetooth_discovery, 1);
|
||||
y->mode = MODE_DISCOVER;
|
||||
y->connection = c;
|
||||
y->callback = cb;
|
||||
y->userdata = u;
|
||||
PA_REFCNT_INIT(y);
|
||||
y->core = c;
|
||||
y->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
|
||||
PA_LLIST_HEAD_INIT(pa_dbus_pending, y->pending);
|
||||
pa_hook_init(&y->hook, y);
|
||||
pa_shared_set(c, "bluetooth-discovery", y);
|
||||
|
||||
if (setup_dbus(y) < 0)
|
||||
goto fail;
|
||||
|
||||
/* dynamic detection of bluetooth audio devices */
|
||||
if (!dbus_connection_add_filter(c, filter_cb, y, NULL)) {
|
||||
if (!dbus_connection_add_filter(pa_dbus_connection_get(y->connection), filter_cb, y, NULL)) {
|
||||
pa_log_error("Failed to add filter function");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pa_dbus_add_matches(
|
||||
c, &err,
|
||||
pa_dbus_connection_get(y->connection), &err,
|
||||
"type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'",
|
||||
"type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'",
|
||||
"type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'",
|
||||
|
|
@ -765,28 +695,46 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_new(DBusConnection *c, pa_bluetoo
|
|||
return y;
|
||||
|
||||
fail:
|
||||
|
||||
if (y)
|
||||
pa_bluetooth_discovery_unref(y);
|
||||
|
||||
dbus_error_free(&err);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pa_bluetooth_discovery_free(pa_bluetooth_discovery *y) {
|
||||
pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y) {
|
||||
pa_assert(y);
|
||||
pa_assert(PA_REFCNT_VALUE(y) > 0);
|
||||
|
||||
PA_REFCNT_INC(y);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
|
||||
pa_bluetooth_device *d;
|
||||
|
||||
pa_assert(y);
|
||||
pa_assert(PA_REFCNT_VALUE(y) > 0);
|
||||
|
||||
if (PA_REFCNT_DEC(y) > 0)
|
||||
return;
|
||||
|
||||
pa_dbus_free_pending_list(&y->pending);
|
||||
|
||||
if (y->devices) {
|
||||
while ((d = pa_hashmap_steal_first(y->devices))) {
|
||||
run_callback(y, d, FALSE);
|
||||
pa_bluetooth_device_free(d);
|
||||
run_callback(y, d, TRUE);
|
||||
device_free(d);
|
||||
}
|
||||
|
||||
pa_hashmap_free(y->devices, NULL, NULL);
|
||||
}
|
||||
|
||||
if (y->connection) {
|
||||
pa_dbus_remove_matches(y->connection,
|
||||
pa_dbus_remove_matches(pa_dbus_connection_get(y->connection),
|
||||
"type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'",
|
||||
"type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterRemoved'",
|
||||
"type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'",
|
||||
|
|
@ -795,16 +743,31 @@ void pa_bluetooth_discovery_free(pa_bluetooth_discovery *y) {
|
|||
"type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
|
||||
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", NULL);
|
||||
|
||||
dbus_connection_remove_filter(y->connection, filter_cb, y);
|
||||
dbus_connection_remove_filter(pa_dbus_connection_get(y->connection), filter_cb, y);
|
||||
|
||||
pa_dbus_connection_unref(y->connection);
|
||||
}
|
||||
|
||||
pa_hook_done(&y->hook);
|
||||
|
||||
if (y->core)
|
||||
pa_shared_remove(y->core, "bluetooth-discovery");
|
||||
}
|
||||
|
||||
void pa_bluetooth_discovery_sync(pa_bluetooth_discovery *y) {
|
||||
pa_assert(y);
|
||||
pa_assert(PA_REFCNT_VALUE(y) > 0);
|
||||
|
||||
pa_dbus_sync_pending_list(&y->pending);
|
||||
}
|
||||
|
||||
pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *y) {
|
||||
pa_assert(y);
|
||||
pa_assert(PA_REFCNT_VALUE(y) > 0);
|
||||
|
||||
return &y->hook;
|
||||
}
|
||||
|
||||
const char*pa_bluetooth_get_form_factor(uint32_t class) {
|
||||
unsigned i;
|
||||
const char *r;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ struct pa_bluetooth_uuid {
|
|||
};
|
||||
|
||||
struct pa_bluetooth_device {
|
||||
void *data; /* arbitrary information for the one owning the discovery object */
|
||||
pa_bool_t dead;
|
||||
|
||||
int device_info_valid; /* 0: no results yet; 1: good results; -1: bad results ... */
|
||||
int audio_sink_info_valid; /* ... same here ... */
|
||||
|
|
@ -64,17 +64,18 @@ struct pa_bluetooth_device {
|
|||
int headset_connected;
|
||||
};
|
||||
|
||||
void pa_bluetooth_device_free(pa_bluetooth_device *d);
|
||||
pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core);
|
||||
pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y);
|
||||
void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *d);
|
||||
|
||||
pa_bluetooth_device* pa_bluetooth_get_device(DBusConnection *c, const char* path);
|
||||
pa_bluetooth_device* pa_bluetooth_find_device(DBusConnection *c, const char* address);
|
||||
|
||||
typedef void (*pa_bluetooth_device_callback_t)(struct userdata *u, pa_bluetooth_device *d, pa_bool_t good);
|
||||
pa_bluetooth_discovery* pa_bluetooth_discovery_new(DBusConnection *c, pa_bluetooth_device_callback_t cb, struct userdata *u);
|
||||
void pa_bluetooth_discovery_free(pa_bluetooth_discovery *d);
|
||||
void pa_bluetooth_discovery_sync(pa_bluetooth_discovery *d);
|
||||
|
||||
const char*pa_bluetooth_get_form_factor(uint32_t class);
|
||||
const pa_bluetooth_device* pa_bluetooth_discovery_get_by_path(pa_bluetooth_discovery *d, const char* path);
|
||||
const pa_bluetooth_device* pa_bluetooth_discovery_get_by_address(pa_bluetooth_discovery *d, const char* address);
|
||||
|
||||
pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *d);
|
||||
|
||||
const char* pa_bluetooth_get_form_factor(uint32_t class);
|
||||
|
||||
char *pa_bluetooth_cleanup_name(const char *name);
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ struct userdata {
|
|||
pa_core *core;
|
||||
pa_module *module;
|
||||
|
||||
char *address;
|
||||
|
||||
pa_card *card;
|
||||
pa_sink *sink;
|
||||
pa_source *source;
|
||||
|
|
@ -153,8 +155,6 @@ struct userdata {
|
|||
|
||||
pa_modargs *modargs;
|
||||
|
||||
pa_bluetooth_device *device;
|
||||
|
||||
int stream_write_type, stream_read_type;
|
||||
int service_write_type, service_read_type;
|
||||
};
|
||||
|
|
@ -331,7 +331,7 @@ static int get_caps(struct userdata *u) {
|
|||
msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
|
||||
msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
|
||||
|
||||
pa_strlcpy(msg.getcaps_req.device, u->device->address, sizeof(msg.getcaps_req.device));
|
||||
pa_strlcpy(msg.getcaps_req.device, u->address, sizeof(msg.getcaps_req.device));
|
||||
if (u->profile == PROFILE_A2DP)
|
||||
msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
|
||||
else {
|
||||
|
|
@ -613,7 +613,7 @@ static int set_conf(struct userdata *u) {
|
|||
msg.setconf_req.h.name = BT_SET_CONFIGURATION;
|
||||
msg.setconf_req.h.length = sizeof(msg.setconf_req);
|
||||
|
||||
pa_strlcpy(msg.setconf_req.device, u->device->address, sizeof(msg.setconf_req.device));
|
||||
pa_strlcpy(msg.setconf_req.device, u->address, sizeof(msg.setconf_req.device));
|
||||
msg.setconf_req.access_mode = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_ACCESS_MODE_WRITE : BT_CAPABILITIES_ACCESS_MODE_READWRITE;
|
||||
|
||||
msg.setconf_req.codec.transport = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_TRANSPORT_A2DP : BT_CAPABILITIES_TRANSPORT_SCO;
|
||||
|
|
@ -1482,7 +1482,7 @@ static int add_sink(struct userdata *u) {
|
|||
pa_sink_new_data_set_sample_spec(&data, &u->sample_spec);
|
||||
pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP ? "a2dp" : "sco");
|
||||
data.card = u->card;
|
||||
data.name = get_name("sink", u->modargs, u->device->address, &b);
|
||||
data.name = get_name("sink", u->modargs, u->address, &b);
|
||||
data.namereg_fail = b;
|
||||
|
||||
u->sink = pa_sink_new(u->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
|
||||
|
|
@ -1526,7 +1526,7 @@ static int add_source(struct userdata *u) {
|
|||
pa_source_new_data_set_sample_spec(&data, &u->sample_spec);
|
||||
pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP ? "a2dp" : "sco");
|
||||
data.card = u->card;
|
||||
data.name = get_name("source", u->modargs, u->device->address, &b);
|
||||
data.name = get_name("source", u->modargs, u->address, &b);
|
||||
data.namereg_fail = b;
|
||||
|
||||
u->source = pa_source_new(u->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
|
||||
|
|
@ -1768,7 +1768,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int add_card(struct userdata *u, const char * default_profile) {
|
||||
static int add_card(struct userdata *u, const char *default_profile, const pa_bluetooth_device *device) {
|
||||
pa_card_new_data data;
|
||||
pa_bool_t b;
|
||||
pa_card_profile *p;
|
||||
|
|
@ -1780,24 +1780,24 @@ static int add_card(struct userdata *u, const char * default_profile) {
|
|||
data.driver = __FILE__;
|
||||
data.module = u->module;
|
||||
|
||||
n = pa_bluetooth_cleanup_name(u->device->name);
|
||||
n = pa_bluetooth_cleanup_name(device->name);
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, n);
|
||||
pa_xfree(n);
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device->address);
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, device->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 = pa_bluetooth_get_form_factor(u->device->class)))
|
||||
if ((ff = pa_bluetooth_get_form_factor(device->class)))
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, ff);
|
||||
pa_proplist_sets(data.proplist, "bluez.path", u->device->path);
|
||||
pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", (unsigned) u->device->class);
|
||||
pa_proplist_sets(data.proplist, "bluez.name", u->device->name);
|
||||
data.name = get_name("card", u->modargs, u->device->address, &b);
|
||||
pa_proplist_sets(data.proplist, "bluez.path", device->path);
|
||||
pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", (unsigned) device->class);
|
||||
pa_proplist_sets(data.proplist, "bluez.name", device->name);
|
||||
data.name = get_name("card", u->modargs, device->address, &b);
|
||||
data.namereg_fail = b;
|
||||
|
||||
data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
|
||||
|
||||
if (u->device->audio_sink_info_valid > 0) {
|
||||
if (device->audio_sink_info_valid > 0) {
|
||||
p = pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP)"), sizeof(enum profile));
|
||||
p->priority = 10;
|
||||
p->n_sinks = 1;
|
||||
|
|
@ -1811,7 +1811,7 @@ static int add_card(struct userdata *u, const char * default_profile) {
|
|||
pa_hashmap_put(data.profiles, p->name, p);
|
||||
}
|
||||
|
||||
if (u->device->headset_info_valid > 0) {
|
||||
if (device->headset_info_valid > 0) {
|
||||
p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(enum profile));
|
||||
p->priority = 20;
|
||||
p->n_sinks = 1;
|
||||
|
|
@ -1856,47 +1856,39 @@ static int add_card(struct userdata *u, const char * default_profile) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int setup_dbus(struct userdata *u) {
|
||||
DBusError error;
|
||||
static const pa_bluetooth_device* find_device(struct userdata *u, pa_bluetooth_discovery *y, const char *address, const char *path) {
|
||||
const pa_bluetooth_device *d = NULL;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
u->connection = pa_dbus_bus_get(u->core, DBUS_BUS_SYSTEM, &error);
|
||||
if (dbus_error_is_set(&error) || (!u->connection)) {
|
||||
pa_log("Failed to get D-Bus connection: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_device(struct userdata *u, const char *address, const char *path) {
|
||||
pa_assert(u);
|
||||
pa_assert(y);
|
||||
|
||||
if (!address && !path) {
|
||||
pa_log_error("Failed to get device address/path from module arguments.");
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
if (!(u->device = pa_bluetooth_get_device(pa_dbus_connection_get(u->connection), path))) {
|
||||
if (!(d = pa_bluetooth_discovery_get_by_path(y, path))) {
|
||||
pa_log_error("%s is not a valid BlueZ audio device.", path);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (address && !(pa_streq(u->device->address, address))) {
|
||||
if (address && !(pa_streq(d->address, address))) {
|
||||
pa_log_error("Passed path %s and address %s don't match.", path, address);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!(u->device = pa_bluetooth_find_device(pa_dbus_connection_get(u->connection), address))) {
|
||||
if (!(d = pa_bluetooth_discovery_get_by_address(y, address))) {
|
||||
pa_log_error("%s is not known.", address);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (d)
|
||||
u->address = pa_xstrdup(d->address);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
int pa__init(pa_module* m) {
|
||||
|
|
@ -1904,6 +1896,8 @@ int pa__init(pa_module* m) {
|
|||
uint32_t channels;
|
||||
struct userdata *u;
|
||||
const char *address, *path;
|
||||
const pa_bluetooth_device *d;
|
||||
pa_bluetooth_discovery *y = NULL;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
|
|
@ -1948,21 +1942,22 @@ int pa__init(pa_module* m) {
|
|||
u->sample_spec.channels = (uint8_t) channels;
|
||||
u->requested_sample_spec = u->sample_spec;
|
||||
|
||||
if (setup_dbus(u) < 0)
|
||||
goto fail;
|
||||
|
||||
address = pa_modargs_get_value(ma, "address", NULL);
|
||||
path = pa_modargs_get_value(ma, "path", NULL);
|
||||
|
||||
if (find_device(u, address, path) < 0)
|
||||
if (!(y = pa_bluetooth_discovery_get(m->core)))
|
||||
goto fail;
|
||||
|
||||
pa_assert(u->device);
|
||||
if (!(d = find_device(u, y, address, path)))
|
||||
goto fail;
|
||||
|
||||
/* Add the card structure. This will also initialize the default profile */
|
||||
if (add_card(u, pa_modargs_get_value(ma, "profile", NULL)) < 0)
|
||||
if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), d) < 0)
|
||||
goto fail;
|
||||
|
||||
pa_bluetooth_discovery_unref(y);
|
||||
y = NULL;
|
||||
|
||||
/* Connect to the BT service and query capabilities */
|
||||
if (init_bt(u) < 0)
|
||||
goto fail;
|
||||
|
|
@ -2014,7 +2009,12 @@ int pa__init(pa_module* m) {
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
if (y)
|
||||
pa_bluetooth_discovery_unref(y);
|
||||
|
||||
pa__done(m);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -2080,9 +2080,6 @@ void pa__done(pa_module *m) {
|
|||
|
||||
shutdown_bt(u);
|
||||
|
||||
if (u->device)
|
||||
pa_bluetooth_device_free(u->device);
|
||||
|
||||
if (u->a2dp.buffer)
|
||||
pa_xfree(u->a2dp.buffer);
|
||||
|
||||
|
|
@ -2091,5 +2088,7 @@ void pa__done(pa_module *m) {
|
|||
if (u->modargs)
|
||||
pa_modargs_free(u->modargs);
|
||||
|
||||
pa_xfree(u->address);
|
||||
|
||||
pa_xfree(u);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,19 +57,28 @@ struct userdata {
|
|||
pa_module *module;
|
||||
pa_modargs *modargs;
|
||||
pa_core *core;
|
||||
pa_dbus_connection *connection;
|
||||
pa_bluetooth_discovery *discovery;
|
||||
pa_hook_slot *slot;
|
||||
pa_hashmap *hashmap;
|
||||
};
|
||||
|
||||
static void load_module_for_device(struct userdata *u, pa_bluetooth_device *d, pa_bool_t good) {
|
||||
static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct userdata *u) {
|
||||
uint32_t midx;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(d);
|
||||
|
||||
if (good &&
|
||||
|
||||
if (!(midx = PA_PTR_TO_UINT(pa_hashmap_get(u->hashmap, d->path))))
|
||||
midx = PA_INVALID_INDEX;
|
||||
else
|
||||
midx--;
|
||||
|
||||
if (!d->dead &&
|
||||
d->device_connected > 0 &&
|
||||
(d->audio_sink_connected > 0 || d->headset_connected > 0)) {
|
||||
|
||||
if (((uint32_t) PA_PTR_TO_UINT(d->data))-1 == PA_INVALID_INDEX) {
|
||||
if (midx == PA_INVALID_INDEX) {
|
||||
pa_module *m = NULL;
|
||||
char *args;
|
||||
|
||||
|
|
@ -93,38 +102,25 @@ static void load_module_for_device(struct userdata *u, pa_bluetooth_device *d, p
|
|||
pa_xfree(args);
|
||||
|
||||
if (m)
|
||||
d->data = PA_UINT_TO_PTR((uint32_t) (m->index+1));
|
||||
pa_hashmap_put(u->hashmap, d->path, PA_UINT_TO_PTR((uint32_t) (m->index+1)));
|
||||
else
|
||||
pa_log_debug("Failed to load module for device %s", d->path);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (((uint32_t) PA_PTR_TO_UINT(d->data))-1 != PA_INVALID_INDEX) {
|
||||
if (midx != PA_INVALID_INDEX) {
|
||||
|
||||
/* Hmm, disconnection? Then let's unload our module */
|
||||
|
||||
pa_log_debug("Unloading module for %s", d->path);
|
||||
pa_module_unload_request_by_index(u->core, (uint32_t) (PA_PTR_TO_UINT(d->data))-1, TRUE);
|
||||
d->data = NULL;
|
||||
pa_module_unload_request_by_index(u->core, midx, TRUE);
|
||||
|
||||
pa_hashmap_remove(u->hashmap, d->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int setup_dbus(struct userdata *u) {
|
||||
DBusError err;
|
||||
|
||||
dbus_error_init(&err);
|
||||
|
||||
u->connection = pa_dbus_bus_get(u->core, DBUS_BUS_SYSTEM, &err);
|
||||
|
||||
if (dbus_error_is_set(&err) || !u->connection) {
|
||||
pa_log("Failed to get D-Bus connection: %s", err.message);
|
||||
dbus_error_free(&err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
||||
int pa__init(pa_module* m) {
|
||||
|
|
@ -149,12 +145,12 @@ int pa__init(pa_module* m) {
|
|||
u->core = m->core;
|
||||
u->modargs = ma;
|
||||
ma = NULL;
|
||||
u->hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
|
||||
|
||||
if (setup_dbus(u) < 0)
|
||||
if (!(u->discovery = pa_bluetooth_discovery_get(u->core)))
|
||||
goto fail;
|
||||
|
||||
if (!(u->discovery = pa_bluetooth_discovery_new(pa_dbus_connection_get(u->connection), load_module_for_device, u)))
|
||||
goto fail;
|
||||
u->slot = pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery), PA_HOOK_NORMAL, (pa_hook_cb_t) load_module_for_device, u);
|
||||
|
||||
if (!async)
|
||||
pa_bluetooth_discovery_sync(u->discovery);
|
||||
|
|
@ -178,11 +174,14 @@ void pa__done(pa_module* m) {
|
|||
if (!(u = m->userdata))
|
||||
return;
|
||||
|
||||
if (u->discovery)
|
||||
pa_bluetooth_discovery_free(u->discovery);
|
||||
if (u->slot)
|
||||
pa_hook_slot_free(u->slot);
|
||||
|
||||
if (u->connection)
|
||||
pa_dbus_connection_unref(u->connection);
|
||||
if (u->discovery)
|
||||
pa_bluetooth_discovery_unref(u->discovery);
|
||||
|
||||
if (u->hashmap)
|
||||
pa_hashmap_free(u->hashmap, NULL, NULL);
|
||||
|
||||
if (u->modargs)
|
||||
pa_modargs_free(u->modargs);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue