mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
Merge branch 'a2dp-swap-source-sink' into 'master'
WIP: bluetooth: Enable swapping A2DP source and sink role See merge request pulseaudio/pulseaudio!480
This commit is contained in:
commit
48d264f340
2 changed files with 51 additions and 29 deletions
|
|
@ -443,11 +443,10 @@ bool pa_bluetooth_device_switch_codec(pa_bluetooth_device *device, pa_bluetooth_
|
||||||
DBusMessageIter iter, dict;
|
DBusMessageIter iter, dict;
|
||||||
DBusMessage *m;
|
DBusMessage *m;
|
||||||
struct switch_codec_data *data;
|
struct switch_codec_data *data;
|
||||||
pa_a2dp_codec_capabilities *capabilities;
|
const pa_a2dp_codec_capabilities *capabilities;
|
||||||
uint8_t config[MAX_A2DP_CAPS_SIZE];
|
uint8_t config[MAX_A2DP_CAPS_SIZE];
|
||||||
uint8_t config_size;
|
uint8_t config_size;
|
||||||
bool is_a2dp_sink;
|
bool is_a2dp_sink;
|
||||||
pa_hashmap *all_endpoints;
|
|
||||||
char *pa_endpoint;
|
char *pa_endpoint;
|
||||||
const char *endpoint;
|
const char *endpoint;
|
||||||
|
|
||||||
|
|
@ -462,13 +461,10 @@ bool pa_bluetooth_device_switch_codec(pa_bluetooth_device *device, pa_bluetooth_
|
||||||
|
|
||||||
is_a2dp_sink = profile == PA_BLUETOOTH_PROFILE_A2DP_SINK;
|
is_a2dp_sink = profile == PA_BLUETOOTH_PROFILE_A2DP_SINK;
|
||||||
|
|
||||||
all_endpoints = NULL;
|
|
||||||
all_endpoints = pa_hashmap_get(is_a2dp_sink ? device->a2dp_sink_endpoints : device->a2dp_source_endpoints,
|
|
||||||
&endpoint_conf->id);
|
|
||||||
pa_assert(all_endpoints);
|
|
||||||
|
|
||||||
pa_assert_se(endpoint = endpoint_conf->choose_remote_endpoint(capabilities_hashmap, &device->discovery->core->default_sample_spec, is_a2dp_sink));
|
pa_assert_se(endpoint = endpoint_conf->choose_remote_endpoint(capabilities_hashmap, &device->discovery->core->default_sample_spec, is_a2dp_sink));
|
||||||
pa_assert_se(capabilities = pa_hashmap_get(all_endpoints, endpoint));
|
pa_assert_se(capabilities = pa_hashmap_get(capabilities_hashmap, endpoint));
|
||||||
|
|
||||||
|
pa_log_info("Switching to codec %s @ %s", endpoint_conf->bt_codec.name, endpoint);
|
||||||
|
|
||||||
config_size = endpoint_conf->fill_preferred_configuration(&device->discovery->core->default_sample_spec,
|
config_size = endpoint_conf->fill_preferred_configuration(&device->discovery->core->default_sample_spec,
|
||||||
capabilities->buffer, capabilities->size, config);
|
capabilities->buffer, capabilities->size, config);
|
||||||
|
|
@ -479,7 +475,7 @@ bool pa_bluetooth_device_switch_codec(pa_bluetooth_device *device, pa_bluetooth_
|
||||||
endpoint_conf->bt_codec.name);
|
endpoint_conf->bt_codec.name);
|
||||||
|
|
||||||
pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, endpoint,
|
pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, endpoint,
|
||||||
BLUEZ_MEDIA_ENDPOINT_INTERFACE, "SetConfiguration"));
|
BLUEZ_MEDIA_ENDPOINT_INTERFACE, "SetConfiguration"));
|
||||||
|
|
||||||
dbus_message_iter_init_append(m, &iter);
|
dbus_message_iter_init_append(m, &iter);
|
||||||
pa_assert_se(dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &pa_endpoint));
|
pa_assert_se(dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &pa_endpoint));
|
||||||
|
|
|
||||||
|
|
@ -1409,6 +1409,8 @@ static int setup_transport(struct userdata *u) {
|
||||||
return -1; /* We need to fail here until the interactions with module-suspend-on-idle and alike get improved */
|
return -1; /* We need to fail here until the interactions with module-suspend-on-idle and alike get improved */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, pa_bluetooth_profile_to_string(t->profile)), false) >= 0);
|
||||||
|
|
||||||
return transport_config(u);
|
return transport_config(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2154,37 +2156,66 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro
|
||||||
|
|
||||||
*p = profile;
|
*p = profile;
|
||||||
|
|
||||||
if (u->device->transports[*p])
|
cp->available = pa_bluetooth_device_supports_profile(u->device, profile) ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
|
||||||
cp->available = transport_state_to_availability(u->device->transports[*p]->state);
|
|
||||||
else
|
|
||||||
cp->available = PA_AVAILABLE_NO;
|
|
||||||
|
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void switch_codec_cb_handler(bool success, pa_bluetooth_profile_t profile, void *userdata);
|
||||||
|
|
||||||
/* Run from main thread */
|
/* Run from main thread */
|
||||||
static int set_profile_cb(pa_card *c, pa_card_profile *new_profile) {
|
static int set_profile_cb(pa_card *c, pa_card_profile *new_profile) {
|
||||||
struct userdata *u;
|
struct userdata *u;
|
||||||
pa_bluetooth_profile_t *p;
|
pa_bluetooth_profile_t p;
|
||||||
|
|
||||||
pa_assert(c);
|
pa_assert(c);
|
||||||
pa_assert(new_profile);
|
pa_assert(new_profile);
|
||||||
pa_assert_se(u = c->userdata);
|
pa_assert_se(u = c->userdata);
|
||||||
|
|
||||||
p = PA_CARD_PROFILE_DATA(new_profile);
|
p = *(pa_bluetooth_profile_t *)PA_CARD_PROFILE_DATA(new_profile);
|
||||||
|
|
||||||
if (*p != PA_BLUETOOTH_PROFILE_OFF) {
|
if (p == u->profile) {
|
||||||
const pa_bluetooth_device *d = u->device;
|
pa_log_debug("Profile %s already selected", pa_bluetooth_profile_to_string(p));
|
||||||
|
return 0;
|
||||||
if (!d->transports[*p] || d->transports[*p]->state <= PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED) {
|
|
||||||
pa_log_warn("Refused to switch profile to %s: Not connected", new_profile->name);
|
|
||||||
return -PA_ERR_IO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_thread(u);
|
stop_thread(u);
|
||||||
|
|
||||||
u->profile = *p;
|
if (p != PA_BLUETOOTH_PROFILE_OFF) {
|
||||||
|
const pa_bluetooth_device *d = u->device;
|
||||||
|
|
||||||
|
if (!d->transports[p] || d->transports[p]->state <= PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED) {
|
||||||
|
if (p != PA_BLUETOOTH_PROFILE_A2DP_SINK && p != PA_BLUETOOTH_PROFILE_A2DP_SOURCE) {
|
||||||
|
pa_log_warn("Refused to switch profile to %s: Not connected", new_profile->name);
|
||||||
|
return -PA_ERR_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_a2dp_sink = p == PA_BLUETOOTH_PROFILE_A2DP_SINK;
|
||||||
|
|
||||||
|
for (int i = 0; i < pa_bluetooth_a2dp_endpoint_conf_count(); ++i) {
|
||||||
|
pa_hashmap *capabilities_hashmap;
|
||||||
|
const pa_a2dp_endpoint_conf *endpoint_conf = pa_bluetooth_a2dp_endpoint_conf_iter(i);
|
||||||
|
|
||||||
|
// Capabilities should already be filtered by this!
|
||||||
|
// if (!pa_bluetooth_a2dp_codec_is_codec_available(&endpoint_conf->id, is_a2dp_sink))
|
||||||
|
// continue;
|
||||||
|
|
||||||
|
capabilities_hashmap = pa_hashmap_get(is_a2dp_sink ? u->device->a2dp_sink_endpoints : u->device->a2dp_source_endpoints, &endpoint_conf->id);
|
||||||
|
if (!capabilities_hashmap)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!pa_bluetooth_device_switch_codec(u->device, p, capabilities_hashmap, endpoint_conf, switch_codec_cb_handler, u))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return PA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_log_warn("Refused to switch profile to %s: ", new_profile->name);
|
||||||
|
return -PA_ERR_IO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u->profile = p;
|
||||||
|
|
||||||
if (u->profile != PA_BLUETOOTH_PROFILE_OFF)
|
if (u->profile != PA_BLUETOOTH_PROFILE_OFF)
|
||||||
if (init_profile(u) < 0)
|
if (init_profile(u) < 0)
|
||||||
|
|
@ -2330,13 +2361,8 @@ static void handle_transport_state_change(struct userdata *u, struct pa_bluetoot
|
||||||
pa_assert(t);
|
pa_assert(t);
|
||||||
pa_assert_se(cp = pa_hashmap_get(u->card->profiles, pa_bluetooth_profile_to_string(t->profile)));
|
pa_assert_se(cp = pa_hashmap_get(u->card->profiles, pa_bluetooth_profile_to_string(t->profile)));
|
||||||
|
|
||||||
|
// TODO: Makes no sense to check this anymore, but maybe that breaks the boolean?
|
||||||
oldavail = cp->available;
|
oldavail = cp->available;
|
||||||
/*
|
|
||||||
* If codec switching is in progress, transport state change should not
|
|
||||||
* make profile unavailable.
|
|
||||||
*/
|
|
||||||
if (!t->device->codec_switching_in_progress)
|
|
||||||
pa_card_profile_set_available(cp, transport_state_to_availability(t->state));
|
|
||||||
|
|
||||||
/* Update port availability */
|
/* Update port availability */
|
||||||
pa_assert_se(port = pa_hashmap_get(u->card->ports, u->output_port_name));
|
pa_assert_se(port = pa_hashmap_get(u->card->ports, u->output_port_name));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue