mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: temporarily remove BAP nodes when another device is switching
Unicast BAP codec switch requires CIG reconfiguration, which cannot be done if there is an acquired transport. When doing BAP codec switch, disable nodes of other devices sharing the same CIG. To avoid problems with node start/stop, just remove and re-add them.
This commit is contained in:
parent
3ed969144a
commit
26b09b0ee3
3 changed files with 81 additions and 11 deletions
|
|
@ -4582,6 +4582,26 @@ static bool codec_switch_clear_bap(struct spa_bt_codec_switch *sw, const char *p
|
|||
return true;
|
||||
}
|
||||
|
||||
static void codec_switch_emit_switching(struct spa_bt_monitor *monitor)
|
||||
{
|
||||
struct spa_bt_device *d;
|
||||
struct spa_bt_codec_switch *sw;
|
||||
bool found = false;
|
||||
|
||||
spa_list_for_each(d, &monitor->device_list, link) {
|
||||
spa_list_for_each(sw, &d->codec_switch_list, link) {
|
||||
if (sw->profiles & SPA_BT_PROFILE_BAP_AUDIO) {
|
||||
found = true;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
spa_list_for_each(d, &monitor->device_list, link)
|
||||
spa_bt_device_emit_codec_switch_other(d, found);
|
||||
}
|
||||
|
||||
static bool codec_switch_process(struct spa_bt_codec_switch *sw)
|
||||
{
|
||||
if (sw->waiting)
|
||||
|
|
@ -4596,6 +4616,9 @@ static bool codec_switch_process(struct spa_bt_codec_switch *sw)
|
|||
spa_log_info(sw->device->monitor->log, "media codec switch %p: success", sw);
|
||||
spa_bt_device_emit_codec_switched(sw->device, 0);
|
||||
spa_bt_device_check_profiles(sw->device, false);
|
||||
|
||||
sw->profiles = 0;
|
||||
codec_switch_emit_switching(sw->device->monitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4610,17 +4633,8 @@ static bool codec_switch_process(struct spa_bt_codec_switch *sw)
|
|||
if (sw->path_idx == 0 && codec_switch_rate_limit(sw))
|
||||
return false;
|
||||
|
||||
if (sw->path_idx == 0) {
|
||||
struct spa_bt_transport *t, *t2;
|
||||
|
||||
/* Force CIG inactive */
|
||||
spa_list_for_each(t, &sw->device->transport_list, link) {
|
||||
spa_bt_transport_release_now(t);
|
||||
spa_list_for_each(t2, &sw->device->monitor->transport_list, link)
|
||||
if (t2->device != sw->device && transport_in_same_cig(t, t2))
|
||||
spa_bt_transport_release_now(t2);
|
||||
}
|
||||
}
|
||||
if (sw->path_idx == 0)
|
||||
codec_switch_emit_switching(sw->device->monitor);
|
||||
|
||||
if (sw->paths[sw->path_idx].clear) {
|
||||
if (!codec_switch_clear_bap(sw, sw->paths[sw->path_idx].path))
|
||||
|
|
@ -4644,6 +4658,9 @@ fail:
|
|||
spa_log_info(sw->device->monitor->log, "media codec switch %p: failed", sw);
|
||||
spa_bt_device_emit_codec_switched(sw->device, -ENODEV);
|
||||
spa_bt_device_check_profiles(sw->device, false);
|
||||
|
||||
sw->profiles = 0;
|
||||
codec_switch_emit_switching(sw->device->monitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ struct impl {
|
|||
|
||||
uint32_t profile;
|
||||
unsigned int switching_codec:1;
|
||||
unsigned int switching_codec_other:1;
|
||||
unsigned int save_profile:1;
|
||||
uint32_t prev_bt_connected_profiles;
|
||||
|
||||
|
|
@ -1161,6 +1162,15 @@ static int emit_nodes(struct impl *this)
|
|||
{
|
||||
struct spa_bt_transport *t;
|
||||
|
||||
switch (this->profile) {
|
||||
case DEVICE_PROFILE_BAP:
|
||||
case DEVICE_PROFILE_BAP_SINK:
|
||||
case DEVICE_PROFILE_BAP_SOURCE:
|
||||
if (this->switching_codec_other)
|
||||
return -EBUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
this->props.codec = 0;
|
||||
|
||||
device_set_update(this, &this->device_set, this->profile);
|
||||
|
|
@ -1459,6 +1469,7 @@ static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_a
|
|||
}
|
||||
|
||||
this->switching_codec = false;
|
||||
|
||||
emit_nodes(this);
|
||||
|
||||
this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
|
||||
|
|
@ -1502,6 +1513,43 @@ static void codec_switched(void *userdata, int status)
|
|||
emit_info(this, false);
|
||||
}
|
||||
|
||||
static void codec_switch_other(void *userdata, bool switching)
|
||||
{
|
||||
struct impl *this = userdata;
|
||||
|
||||
this->switching_codec_other = switching;
|
||||
|
||||
switch (this->profile) {
|
||||
case DEVICE_PROFILE_BAP:
|
||||
case DEVICE_PROFILE_BAP_SINK:
|
||||
case DEVICE_PROFILE_BAP_SOURCE:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
spa_log_debug(this->log, "%p: BAP codec switching by another device, switching:%d",
|
||||
this, (int)switching);
|
||||
|
||||
/*
|
||||
* In unicast BAP, output/input must be halted when another device is
|
||||
* switching codec, because CIG must be torn down before it can be
|
||||
* reconfigured. Easiest way to do this and to suspend output/input is to
|
||||
* remove the nodes.
|
||||
*/
|
||||
if (!find_device_transport(this->bt_dev, SPA_BT_PROFILE_BAP_SINK) &&
|
||||
!find_device_transport(this->bt_dev, SPA_BT_PROFILE_BAP_SOURCE))
|
||||
return;
|
||||
|
||||
if (switching) {
|
||||
emit_remove_nodes(this);
|
||||
spa_bt_device_release_transports(this->bt_dev);
|
||||
} else {
|
||||
emit_remove_nodes(this);
|
||||
emit_nodes(this);
|
||||
}
|
||||
}
|
||||
|
||||
static bool device_set_needs_update(struct impl *this)
|
||||
{
|
||||
struct device_set dset = { .impl = this };
|
||||
|
|
@ -1655,6 +1703,7 @@ static const struct spa_bt_device_events bt_dev_events = {
|
|||
SPA_VERSION_BT_DEVICE_EVENTS,
|
||||
.connected = device_connected,
|
||||
.codec_switched = codec_switched,
|
||||
.codec_switch_other = codec_switch_other,
|
||||
.profiles_changed = profiles_changed,
|
||||
.device_set_changed = device_set_changed,
|
||||
.switch_profile = device_switch_profile,
|
||||
|
|
|
|||
|
|
@ -489,6 +489,9 @@ struct spa_bt_device_events {
|
|||
/** Codec switching completed */
|
||||
void (*codec_switched) (void *data, int status);
|
||||
|
||||
/** Codec switching initiated or completed by another device */
|
||||
void (*codec_switch_other) (void *data, bool switching);
|
||||
|
||||
/** Profile configuration changed */
|
||||
void (*profiles_changed) (void *data, uint32_t connected_change);
|
||||
|
||||
|
|
@ -590,6 +593,7 @@ const struct media_codec *spa_bt_get_hfp_codec(struct spa_bt_monitor *monitor, u
|
|||
m, v, ##__VA_ARGS__)
|
||||
#define spa_bt_device_emit_connected(d,...) spa_bt_device_emit(d, connected, 0, __VA_ARGS__)
|
||||
#define spa_bt_device_emit_codec_switched(d,...) spa_bt_device_emit(d, codec_switched, 0, __VA_ARGS__)
|
||||
#define spa_bt_device_emit_codec_switch_other(d,...) spa_bt_device_emit(d, codec_switch_other, 0, __VA_ARGS__)
|
||||
#define spa_bt_device_emit_profiles_changed(d,...) spa_bt_device_emit(d, profiles_changed, 0, __VA_ARGS__)
|
||||
#define spa_bt_device_emit_device_set_changed(d) spa_bt_device_emit(d, device_set_changed, 0)
|
||||
#define spa_bt_device_emit_switch_profile(d) spa_bt_device_emit(d, switch_profile, 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue