mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: Add LE Audio BAP support to media-codecs
This commit is contained in:
parent
00d51c3d31
commit
fd0bcb1699
6 changed files with 102 additions and 35 deletions
|
|
@ -431,9 +431,16 @@ static void register_battery_provider(struct spa_bt_device *device)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int media_codec_to_endpoint(const struct media_codec *codec,
|
static int media_codec_to_endpoint(const struct media_codec *codec,
|
||||||
const char * endpoint,
|
enum spa_bt_media_direction direction,
|
||||||
char** object_path)
|
char** object_path)
|
||||||
{
|
{
|
||||||
|
const char * endpoint;
|
||||||
|
|
||||||
|
if (direction == SPA_BT_MEDIA_SOURCE)
|
||||||
|
endpoint = codec->bap ? BAP_SOURCE_ENDPOINT : A2DP_SOURCE_ENDPOINT;
|
||||||
|
else
|
||||||
|
endpoint = codec->bap ? BAP_SINK_ENDPOINT : A2DP_SINK_ENDPOINT;
|
||||||
|
|
||||||
*object_path = spa_aprintf("%s/%s", endpoint,
|
*object_path = spa_aprintf("%s/%s", endpoint,
|
||||||
codec->endpoint_name ? codec->endpoint_name : codec->name);
|
codec->endpoint_name ? codec->endpoint_name : codec->name);
|
||||||
if (*object_path == NULL)
|
if (*object_path == NULL)
|
||||||
|
|
@ -453,7 +460,14 @@ static const struct media_codec *media_endpoint_to_codec(struct spa_bt_monitor *
|
||||||
} else if (spa_strstartswith(endpoint, A2DP_SOURCE_ENDPOINT "/")) {
|
} else if (spa_strstartswith(endpoint, A2DP_SOURCE_ENDPOINT "/")) {
|
||||||
ep_name = endpoint + strlen(A2DP_SOURCE_ENDPOINT "/");
|
ep_name = endpoint + strlen(A2DP_SOURCE_ENDPOINT "/");
|
||||||
*sink = false;
|
*sink = false;
|
||||||
|
} else if (spa_strstartswith(endpoint, BAP_SOURCE_ENDPOINT "/")) {
|
||||||
|
ep_name = endpoint + strlen(BAP_SOURCE_ENDPOINT "/");
|
||||||
|
*sink = false;
|
||||||
|
} else if (spa_strstartswith(endpoint, BAP_SINK_ENDPOINT "/")) {
|
||||||
|
ep_name = endpoint + strlen(BAP_SINK_ENDPOINT "/");
|
||||||
|
*sink = true;
|
||||||
} else {
|
} else {
|
||||||
|
*sink = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,6 +488,10 @@ static int media_endpoint_to_profile(const char *endpoint)
|
||||||
return SPA_BT_PROFILE_A2DP_SOURCE;
|
return SPA_BT_PROFILE_A2DP_SOURCE;
|
||||||
else if (spa_strstartswith(endpoint, A2DP_SOURCE_ENDPOINT "/"))
|
else if (spa_strstartswith(endpoint, A2DP_SOURCE_ENDPOINT "/"))
|
||||||
return SPA_BT_PROFILE_A2DP_SINK;
|
return SPA_BT_PROFILE_A2DP_SINK;
|
||||||
|
else if (spa_strstartswith(endpoint, BAP_SINK_ENDPOINT "/"))
|
||||||
|
return SPA_BT_PROFILE_BAP_SOURCE;
|
||||||
|
else if (spa_strstartswith(endpoint, BAP_SOURCE_ENDPOINT "/"))
|
||||||
|
return SPA_BT_PROFILE_BAP_SINK;
|
||||||
else
|
else
|
||||||
return SPA_BT_PROFILE_NULL;
|
return SPA_BT_PROFILE_NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -837,6 +855,11 @@ static uint32_t adapter_connectable_profiles(struct spa_bt_adapter *adapter)
|
||||||
if (profiles & SPA_BT_PROFILE_A2DP_SOURCE)
|
if (profiles & SPA_BT_PROFILE_A2DP_SOURCE)
|
||||||
mask |= SPA_BT_PROFILE_A2DP_SINK;
|
mask |= SPA_BT_PROFILE_A2DP_SINK;
|
||||||
|
|
||||||
|
if (profiles & SPA_BT_PROFILE_BAP_SINK)
|
||||||
|
mask |= SPA_BT_PROFILE_BAP_SOURCE;
|
||||||
|
if (profiles & SPA_BT_PROFILE_BAP_SOURCE)
|
||||||
|
mask |= SPA_BT_PROFILE_BAP_SINK;
|
||||||
|
|
||||||
if (profiles & SPA_BT_PROFILE_HSP_AG)
|
if (profiles & SPA_BT_PROFILE_HSP_AG)
|
||||||
mask |= SPA_BT_PROFILE_HSP_HS;
|
mask |= SPA_BT_PROFILE_HSP_HS;
|
||||||
if (profiles & SPA_BT_PROFILE_HSP_HS)
|
if (profiles & SPA_BT_PROFILE_HSP_HS)
|
||||||
|
|
@ -1208,6 +1231,10 @@ static int reconnect_device_profiles(struct spa_bt_device *device)
|
||||||
device_try_connect_profile(device, SPA_BT_UUID_A2DP_SINK);
|
device_try_connect_profile(device, SPA_BT_UUID_A2DP_SINK);
|
||||||
if (reconnect & SPA_BT_PROFILE_A2DP_SOURCE)
|
if (reconnect & SPA_BT_PROFILE_A2DP_SOURCE)
|
||||||
device_try_connect_profile(device, SPA_BT_UUID_A2DP_SOURCE);
|
device_try_connect_profile(device, SPA_BT_UUID_A2DP_SOURCE);
|
||||||
|
if (reconnect & SPA_BT_PROFILE_BAP_SINK)
|
||||||
|
device_try_connect_profile(device, SPA_BT_UUID_BAP_SINK);
|
||||||
|
if (reconnect & SPA_BT_PROFILE_BAP_SOURCE)
|
||||||
|
device_try_connect_profile(device, SPA_BT_UUID_BAP_SOURCE);
|
||||||
|
|
||||||
return reconnect;
|
return reconnect;
|
||||||
}
|
}
|
||||||
|
|
@ -1295,8 +1322,8 @@ int spa_bt_device_check_profiles(struct spa_bt_device *device, bool force)
|
||||||
uint32_t connectable_profiles =
|
uint32_t connectable_profiles =
|
||||||
device->adapter ? adapter_connectable_profiles(device->adapter) : 0;
|
device->adapter ? adapter_connectable_profiles(device->adapter) : 0;
|
||||||
uint32_t direction_masks[3] = {
|
uint32_t direction_masks[3] = {
|
||||||
SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_HEADSET_HEAD_UNIT,
|
SPA_BT_PROFILE_MEDIA_SINK | SPA_BT_PROFILE_HEADSET_HEAD_UNIT,
|
||||||
SPA_BT_PROFILE_A2DP_SOURCE,
|
SPA_BT_PROFILE_MEDIA_SOURCE,
|
||||||
SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY,
|
SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY,
|
||||||
};
|
};
|
||||||
bool direction_connected = false;
|
bool direction_connected = false;
|
||||||
|
|
@ -1514,12 +1541,12 @@ static int device_update_props(struct spa_bt_device *device,
|
||||||
|
|
||||||
profile = spa_bt_profile_from_uuid(uuid);
|
profile = spa_bt_profile_from_uuid(uuid);
|
||||||
|
|
||||||
/* Only add A2DP profiles if HSP/HFP backed is none.
|
/* Only add A2DP/BAP profiles if HSP/HFP backed is none.
|
||||||
* This allows BT device to connect instantly instead of waiting for
|
* This allows BT device to connect instantly instead of waiting for
|
||||||
* profile timeout, because all available profiles are connected.
|
* profile timeout, because all available profiles are connected.
|
||||||
*/
|
*/
|
||||||
if (monitor->backend_selection != BACKEND_NONE || (monitor->backend_selection == BACKEND_NONE &&
|
if (monitor->backend_selection != BACKEND_NONE || (monitor->backend_selection == BACKEND_NONE &&
|
||||||
profile & (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_A2DP_SOURCE))) {
|
profile & (SPA_BT_PROFILE_MEDIA_SINK | SPA_BT_PROFILE_MEDIA_SOURCE))) {
|
||||||
if (profile && (device->profiles & profile) == 0) {
|
if (profile && (device->profiles & profile) == 0) {
|
||||||
spa_log_debug(monitor->log, "device %p: add UUID=%s", device, uuid);
|
spa_log_debug(monitor->log, "device %p: add UUID=%s", device, uuid);
|
||||||
device->profiles |= profile;
|
device->profiles |= profile;
|
||||||
|
|
@ -1587,8 +1614,12 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru
|
||||||
|
|
||||||
spa_list_for_each(ep, &device->remote_endpoint_list, device_link) {
|
spa_list_for_each(ep, &device->remote_endpoint_list, device_link) {
|
||||||
const enum spa_bt_profile profile = spa_bt_profile_from_uuid(ep->uuid);
|
const enum spa_bt_profile profile = spa_bt_profile_from_uuid(ep->uuid);
|
||||||
const enum spa_bt_profile expected = sink ?
|
enum spa_bt_profile expected;
|
||||||
SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE;
|
|
||||||
|
if (codec->bap)
|
||||||
|
expected = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE;
|
||||||
|
else
|
||||||
|
expected = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE;
|
||||||
|
|
||||||
if (profile != expected)
|
if (profile != expected)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -2229,6 +2260,12 @@ static int transport_update_props(struct spa_bt_transport *transport,
|
||||||
case SPA_BT_PROFILE_A2DP_SINK:
|
case SPA_BT_PROFILE_A2DP_SINK:
|
||||||
transport->profile = SPA_BT_PROFILE_A2DP_SOURCE;
|
transport->profile = SPA_BT_PROFILE_A2DP_SOURCE;
|
||||||
break;
|
break;
|
||||||
|
case SPA_BT_PROFILE_BAP_SOURCE:
|
||||||
|
transport->profile = SPA_BT_PROFILE_BAP_SINK;
|
||||||
|
break;
|
||||||
|
case SPA_BT_PROFILE_BAP_SINK:
|
||||||
|
transport->profile = SPA_BT_PROFILE_BAP_SOURCE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
spa_log_warn(monitor->log, "unknown profile %s", value);
|
spa_log_warn(monitor->log, "unknown profile %s", value);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2577,7 +2614,7 @@ static bool media_codec_switch_process_current(struct spa_bt_media_codec_switch
|
||||||
struct spa_bt_transport *t;
|
struct spa_bt_transport *t;
|
||||||
const struct media_codec *codec;
|
const struct media_codec *codec;
|
||||||
uint8_t config[A2DP_MAX_CAPS_SIZE];
|
uint8_t config[A2DP_MAX_CAPS_SIZE];
|
||||||
char *local_endpoint_base;
|
enum spa_bt_media_direction direction;
|
||||||
char *local_endpoint = NULL;
|
char *local_endpoint = NULL;
|
||||||
int res, config_size;
|
int res, config_size;
|
||||||
dbus_bool_t dbus_ret;
|
dbus_bool_t dbus_ret;
|
||||||
|
|
@ -2613,11 +2650,11 @@ static bool media_codec_switch_process_current(struct spa_bt_media_codec_switch
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sw->profile & SPA_BT_PROFILE_A2DP_SINK) {
|
if ((sw->profile & SPA_BT_PROFILE_A2DP_SINK) || (sw->profile & SPA_BT_PROFILE_BAP_SINK) ) {
|
||||||
local_endpoint_base = A2DP_SOURCE_ENDPOINT;
|
direction = SPA_BT_MEDIA_SOURCE;
|
||||||
sink = false;
|
sink = false;
|
||||||
} else if (sw->profile & SPA_BT_PROFILE_A2DP_SOURCE) {
|
} else if ((sw->profile & SPA_BT_PROFILE_A2DP_SOURCE) || (sw->profile & SPA_BT_PROFILE_BAP_SOURCE) ) {
|
||||||
local_endpoint_base = A2DP_SINK_ENDPOINT;
|
direction = SPA_BT_MEDIA_SINK;
|
||||||
sink = true;
|
sink = true;
|
||||||
} else {
|
} else {
|
||||||
spa_log_debug(sw->device->monitor->log, "media codec switch %p: bad profile (%d), try next",
|
spa_log_debug(sw->device->monitor->log, "media codec switch %p: bad profile (%d), try next",
|
||||||
|
|
@ -2625,7 +2662,7 @@ static bool media_codec_switch_process_current(struct spa_bt_media_codec_switch
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media_codec_to_endpoint(codec, local_endpoint_base, &local_endpoint) < 0) {
|
if (media_codec_to_endpoint(codec, direction, &local_endpoint) < 0) {
|
||||||
spa_log_debug(sw->device->monitor->log, "media codec switch %p: no endpoint for codec %s, try next",
|
spa_log_debug(sw->device->monitor->log, "media codec switch %p: no endpoint for codec %s, try next",
|
||||||
sw, codec->name);
|
sw, codec->name);
|
||||||
goto next;
|
goto next;
|
||||||
|
|
@ -2912,7 +2949,10 @@ static int media_codec_switch_cmp(const void *a, const void *b)
|
||||||
else if (ep2 == NULL)
|
else if (ep2 == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
flags = spa_streq(ep1->uuid, SPA_BT_UUID_A2DP_SOURCE) ? MEDIA_CODEC_FLAG_SINK : 0;
|
if (codec->bap)
|
||||||
|
flags = spa_streq(ep1->uuid, SPA_BT_UUID_BAP_SOURCE) ? MEDIA_CODEC_FLAG_SINK : 0;
|
||||||
|
else
|
||||||
|
flags = spa_streq(ep1->uuid, SPA_BT_UUID_A2DP_SOURCE) ? MEDIA_CODEC_FLAG_SINK : 0;
|
||||||
|
|
||||||
return codec->caps_preference_cmp(codec, flags, ep1->capabilities, ep1->capabilities_len,
|
return codec->caps_preference_cmp(codec, flags, ep1->capabilities, ep1->capabilities_len,
|
||||||
ep2->capabilities, ep2->capabilities_len, &sw->device->monitor->default_audio_info,
|
ep2->capabilities, ep2->capabilities_len, &sw->device->monitor->default_audio_info,
|
||||||
|
|
@ -3303,7 +3343,7 @@ static void append_basic_array_variant_dict_entry(DBusMessageIter *dict, const c
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bluez_register_endpoint(struct spa_bt_monitor *monitor,
|
static int bluez_register_endpoint(struct spa_bt_monitor *monitor,
|
||||||
const char *path, const char *endpoint,
|
const char *path, enum spa_bt_media_direction direction,
|
||||||
const char *uuid, const struct media_codec *codec) {
|
const char *uuid, const struct media_codec *codec) {
|
||||||
char *object_path = NULL;
|
char *object_path = NULL;
|
||||||
DBusMessage *m;
|
DBusMessage *m;
|
||||||
|
|
@ -3312,14 +3352,12 @@ static int bluez_register_endpoint(struct spa_bt_monitor *monitor,
|
||||||
uint8_t caps[A2DP_MAX_CAPS_SIZE];
|
uint8_t caps[A2DP_MAX_CAPS_SIZE];
|
||||||
int ret, caps_size;
|
int ret, caps_size;
|
||||||
uint16_t codec_id = codec->codec_id;
|
uint16_t codec_id = codec->codec_id;
|
||||||
bool sink;
|
bool sink = (direction == SPA_BT_MEDIA_SINK);
|
||||||
|
|
||||||
ret = media_codec_to_endpoint(codec, endpoint, &object_path);
|
ret = media_codec_to_endpoint(codec, direction, &object_path);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
sink = spa_streq(endpoint, A2DP_SINK_ENDPOINT);
|
|
||||||
|
|
||||||
ret = caps_size = codec->fill_caps(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, caps);
|
ret = caps_size = codec->fill_caps(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, caps);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -3358,7 +3396,7 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int register_media_endpoint(struct spa_bt_monitor *monitor,
|
static int register_media_endpoint(struct spa_bt_monitor *monitor,
|
||||||
const struct media_codec *codec, const char *endpoint)
|
const struct media_codec *codec, enum spa_bt_media_direction direction)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char* object_path = NULL;
|
char* object_path = NULL;
|
||||||
|
|
@ -3366,7 +3404,7 @@ static int register_media_endpoint(struct spa_bt_monitor *monitor,
|
||||||
.message_function = endpoint_handler,
|
.message_function = endpoint_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
ret = media_codec_to_endpoint(codec, endpoint, &object_path);
|
ret = media_codec_to_endpoint(codec, direction, &object_path);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
@ -3413,13 +3451,13 @@ static int adapter_register_endpoints(struct spa_bt_adapter *a)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((err = bluez_register_endpoint(monitor, a->path,
|
if ((err = bluez_register_endpoint(monitor, a->path,
|
||||||
A2DP_SOURCE_ENDPOINT,
|
SPA_BT_MEDIA_SOURCE,
|
||||||
SPA_BT_UUID_A2DP_SOURCE,
|
SPA_BT_UUID_A2DP_SOURCE,
|
||||||
codec)))
|
codec)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if ((err = bluez_register_endpoint(monitor, a->path,
|
if ((err = bluez_register_endpoint(monitor, a->path,
|
||||||
A2DP_SINK_ENDPOINT,
|
SPA_BT_MEDIA_SINK,
|
||||||
SPA_BT_UUID_A2DP_SINK,
|
SPA_BT_UUID_A2DP_SINK,
|
||||||
codec)))
|
codec)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -3523,10 +3561,11 @@ static DBusHandlerResult object_manager_handler(DBusConnection *c, DBusMessage *
|
||||||
if (caps_size < 0)
|
if (caps_size < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = media_codec_to_endpoint(codec, A2DP_SINK_ENDPOINT, &endpoint);
|
ret = media_codec_to_endpoint(codec, SPA_BT_MEDIA_SINK, &endpoint);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
spa_log_info(monitor->log, "register media sink codec %s: %s", media_codecs[i]->name, endpoint);
|
spa_log_info(monitor->log, "register media sink codec %s: %s", media_codecs[i]->name, endpoint);
|
||||||
append_media_object(&array, endpoint, SPA_BT_UUID_A2DP_SINK,
|
append_media_object(&array, endpoint,
|
||||||
|
codec->bap ? SPA_BT_UUID_BAP_SINK : SPA_BT_UUID_A2DP_SINK,
|
||||||
codec_id, caps, caps_size);
|
codec_id, caps, caps_size);
|
||||||
free(endpoint);
|
free(endpoint);
|
||||||
}
|
}
|
||||||
|
|
@ -3537,10 +3576,11 @@ static DBusHandlerResult object_manager_handler(DBusConnection *c, DBusMessage *
|
||||||
if (caps_size < 0)
|
if (caps_size < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = media_codec_to_endpoint(codec, A2DP_SOURCE_ENDPOINT, &endpoint);
|
ret = media_codec_to_endpoint(codec, SPA_BT_MEDIA_SOURCE, &endpoint);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
spa_log_info(monitor->log, "register media source codec %s: %s", media_codecs[i]->name, endpoint);
|
spa_log_info(monitor->log, "register media source codec %s: %s", media_codecs[i]->name, endpoint);
|
||||||
append_media_object(&array, endpoint, SPA_BT_UUID_A2DP_SOURCE,
|
append_media_object(&array, endpoint,
|
||||||
|
codec->bap ? SPA_BT_UUID_BAP_SOURCE : SPA_BT_UUID_A2DP_SOURCE,
|
||||||
codec_id, caps, caps_size);
|
codec_id, caps, caps_size);
|
||||||
free(endpoint);
|
free(endpoint);
|
||||||
}
|
}
|
||||||
|
|
@ -3612,9 +3652,9 @@ static int register_media_application(struct spa_bt_monitor * monitor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (codec->encode != NULL)
|
if (codec->encode != NULL)
|
||||||
register_media_endpoint(monitor, codec, A2DP_SOURCE_ENDPOINT);
|
register_media_endpoint(monitor, codec, SPA_BT_MEDIA_SOURCE);
|
||||||
if (codec->decode != NULL)
|
if (codec->decode != NULL)
|
||||||
register_media_endpoint(monitor, codec, A2DP_SINK_ENDPOINT);
|
register_media_endpoint(monitor, codec, SPA_BT_MEDIA_SINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -3632,13 +3672,13 @@ static void unregister_media_application(struct spa_bt_monitor * monitor)
|
||||||
if (!is_media_codec_enabled(monitor, codec))
|
if (!is_media_codec_enabled(monitor, codec))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = media_codec_to_endpoint(codec, A2DP_SOURCE_ENDPOINT, &object_path);
|
ret = media_codec_to_endpoint(codec, SPA_BT_MEDIA_SOURCE, &object_path);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
dbus_connection_unregister_object_path(monitor->conn, object_path);
|
dbus_connection_unregister_object_path(monitor->conn, object_path);
|
||||||
free(object_path);
|
free(object_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = media_codec_to_endpoint(codec, A2DP_SINK_ENDPOINT, &object_path);
|
ret = media_codec_to_endpoint(codec, SPA_BT_MEDIA_SINK, &object_path);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
dbus_connection_unregister_object_path(monitor->conn, object_path);
|
dbus_connection_unregister_object_path(monitor->conn, object_path);
|
||||||
free(object_path);
|
free(object_path);
|
||||||
|
|
@ -4397,6 +4437,10 @@ int spa_bt_profiles_from_json_array(const char *str)
|
||||||
profiles |= SPA_BT_PROFILE_A2DP_SINK;
|
profiles |= SPA_BT_PROFILE_A2DP_SINK;
|
||||||
} else if (spa_streq(role_name, "a2dp_source")) {
|
} else if (spa_streq(role_name, "a2dp_source")) {
|
||||||
profiles |= SPA_BT_PROFILE_A2DP_SOURCE;
|
profiles |= SPA_BT_PROFILE_A2DP_SOURCE;
|
||||||
|
} else if (spa_streq(role_name, "bap_sink")) {
|
||||||
|
profiles |= SPA_BT_PROFILE_BAP_SINK;
|
||||||
|
} else if (spa_streq(role_name, "bap_source")) {
|
||||||
|
profiles |= SPA_BT_PROFILE_BAP_SOURCE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -912,7 +912,7 @@ static void profiles_changed(void *userdata, uint32_t prev_profiles, uint32_t pr
|
||||||
if (this->switching_codec)
|
if (this->switching_codec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SINK) {
|
if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_MEDIA_SINK) {
|
||||||
free(this->supported_codecs);
|
free(this->supported_codecs);
|
||||||
this->supported_codecs = spa_bt_device_get_supported_media_codecs(
|
this->supported_codecs = spa_bt_device_get_supported_media_codecs(
|
||||||
this->bt_dev, &this->supported_codec_count, true);
|
this->bt_dev, &this->supported_codec_count, true);
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,8 @@ extern "C" {
|
||||||
#define SPA_BT_UUID_HSP_AG "00001112-0000-1000-8000-00805f9b34fb"
|
#define SPA_BT_UUID_HSP_AG "00001112-0000-1000-8000-00805f9b34fb"
|
||||||
#define SPA_BT_UUID_HFP_HF "0000111e-0000-1000-8000-00805f9b34fb"
|
#define SPA_BT_UUID_HFP_HF "0000111e-0000-1000-8000-00805f9b34fb"
|
||||||
#define SPA_BT_UUID_HFP_AG "0000111f-0000-1000-8000-00805f9b34fb"
|
#define SPA_BT_UUID_HFP_AG "0000111f-0000-1000-8000-00805f9b34fb"
|
||||||
|
#define SPA_BT_UUID_BAP_SINK "00002bc9-0000-1000-8000-00805f9b34fb"
|
||||||
|
#define SPA_BT_UUID_BAP_SOURCE "00002bcb-0000-1000-8000-00805f9b34fb"
|
||||||
|
|
||||||
#define PROFILE_HSP_AG "/Profile/HSPAG"
|
#define PROFILE_HSP_AG "/Profile/HSPAG"
|
||||||
#define PROFILE_HSP_HS "/Profile/HSPHS"
|
#define PROFILE_HSP_HS "/Profile/HSPHS"
|
||||||
|
|
@ -162,6 +164,9 @@ extern "C" {
|
||||||
#define A2DP_SINK_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/A2DPSink"
|
#define A2DP_SINK_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/A2DPSink"
|
||||||
#define A2DP_SOURCE_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/A2DPSource"
|
#define A2DP_SOURCE_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/A2DPSource"
|
||||||
|
|
||||||
|
#define BAP_SINK_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/BAPSink"
|
||||||
|
#define BAP_SOURCE_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/BAPSource"
|
||||||
|
|
||||||
#define SPA_BT_UNKNOWN_DELAY 0
|
#define SPA_BT_UNKNOWN_DELAY 0
|
||||||
|
|
||||||
#define SPA_BT_NO_BATTERY ((uint8_t)255)
|
#define SPA_BT_NO_BATTERY ((uint8_t)255)
|
||||||
|
|
@ -172,6 +177,11 @@ extern "C" {
|
||||||
#define MSBC_ENCODED_SIZE 60 /* 2 bytes header + 57 mSBC payload + 1 byte padding */
|
#define MSBC_ENCODED_SIZE 60 /* 2 bytes header + 57 mSBC payload + 1 byte padding */
|
||||||
#define MSBC_PAYLOAD_SIZE 57
|
#define MSBC_PAYLOAD_SIZE 57
|
||||||
|
|
||||||
|
enum spa_bt_media_direction {
|
||||||
|
SPA_BT_MEDIA_SOURCE,
|
||||||
|
SPA_BT_MEDIA_SINK,
|
||||||
|
};
|
||||||
|
|
||||||
enum spa_bt_profile {
|
enum spa_bt_profile {
|
||||||
SPA_BT_PROFILE_NULL = 0,
|
SPA_BT_PROFILE_NULL = 0,
|
||||||
SPA_BT_PROFILE_A2DP_SINK = (1 << 0),
|
SPA_BT_PROFILE_A2DP_SINK = (1 << 0),
|
||||||
|
|
@ -180,11 +190,16 @@ enum spa_bt_profile {
|
||||||
SPA_BT_PROFILE_HSP_AG = (1 << 3),
|
SPA_BT_PROFILE_HSP_AG = (1 << 3),
|
||||||
SPA_BT_PROFILE_HFP_HF = (1 << 4),
|
SPA_BT_PROFILE_HFP_HF = (1 << 4),
|
||||||
SPA_BT_PROFILE_HFP_AG = (1 << 5),
|
SPA_BT_PROFILE_HFP_AG = (1 << 5),
|
||||||
|
SPA_BT_PROFILE_BAP_SINK = (1 << 6),
|
||||||
|
SPA_BT_PROFILE_BAP_SOURCE = (1 << 7),
|
||||||
|
|
||||||
SPA_BT_PROFILE_A2DP_DUPLEX = (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_A2DP_SOURCE),
|
SPA_BT_PROFILE_A2DP_DUPLEX = (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_A2DP_SOURCE),
|
||||||
SPA_BT_PROFILE_HEADSET_HEAD_UNIT = (SPA_BT_PROFILE_HSP_HS | SPA_BT_PROFILE_HFP_HF),
|
SPA_BT_PROFILE_HEADSET_HEAD_UNIT = (SPA_BT_PROFILE_HSP_HS | SPA_BT_PROFILE_HFP_HF),
|
||||||
SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY = (SPA_BT_PROFILE_HSP_AG | SPA_BT_PROFILE_HFP_AG),
|
SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY = (SPA_BT_PROFILE_HSP_AG | SPA_BT_PROFILE_HFP_AG),
|
||||||
SPA_BT_PROFILE_HEADSET_AUDIO = (SPA_BT_PROFILE_HEADSET_HEAD_UNIT | SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY),
|
SPA_BT_PROFILE_HEADSET_AUDIO = (SPA_BT_PROFILE_HEADSET_HEAD_UNIT | SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY),
|
||||||
|
|
||||||
|
SPA_BT_PROFILE_MEDIA_SINK = (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_BAP_SINK),
|
||||||
|
SPA_BT_PROFILE_MEDIA_SOURCE = (SPA_BT_PROFILE_A2DP_SOURCE | SPA_BT_PROFILE_BAP_SOURCE),
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline enum spa_bt_profile spa_bt_profile_from_uuid(const char *uuid)
|
static inline enum spa_bt_profile spa_bt_profile_from_uuid(const char *uuid)
|
||||||
|
|
@ -203,6 +218,10 @@ static inline enum spa_bt_profile spa_bt_profile_from_uuid(const char *uuid)
|
||||||
return SPA_BT_PROFILE_HFP_HF;
|
return SPA_BT_PROFILE_HFP_HF;
|
||||||
else if (strcasecmp(uuid, SPA_BT_UUID_HFP_AG) == 0)
|
else if (strcasecmp(uuid, SPA_BT_UUID_HFP_AG) == 0)
|
||||||
return SPA_BT_PROFILE_HFP_AG;
|
return SPA_BT_PROFILE_HFP_AG;
|
||||||
|
else if (strcasecmp(uuid, SPA_BT_UUID_BAP_SINK) == 0)
|
||||||
|
return SPA_BT_PROFILE_BAP_SINK;
|
||||||
|
else if (strcasecmp(uuid, SPA_BT_UUID_BAP_SOURCE) == 0)
|
||||||
|
return SPA_BT_PROFILE_BAP_SOURCE;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,8 @@ struct media_codec {
|
||||||
uint8_t codec_id;
|
uint8_t codec_id;
|
||||||
a2dp_vendor_codec_t vendor;
|
a2dp_vendor_codec_t vendor;
|
||||||
|
|
||||||
|
bool bap;
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *description;
|
const char *description;
|
||||||
const char *endpoint_name; /**< Endpoint name. If NULL, same as name */
|
const char *endpoint_name; /**< Endpoint name. If NULL, same as name */
|
||||||
|
|
|
||||||
|
|
@ -920,7 +920,8 @@ static int do_start(struct impl *this)
|
||||||
if (this->codec_data == NULL)
|
if (this->codec_data == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
spa_log_info(this->log, "%p: using A2DP codec %s, delay:%"PRIi64" ms", this, this->codec->description,
|
spa_log_info(this->log, "%p: using %s codec %s, delay:%"PRIi64" ms", this,
|
||||||
|
this->codec->bap ? "BAP" : "A2DP", this->codec->description,
|
||||||
(int64_t)(spa_bt_transport_get_delay_nsec(this->transport) / SPA_NSEC_PER_MSEC));
|
(int64_t)(spa_bt_transport_get_delay_nsec(this->transport) / SPA_NSEC_PER_MSEC));
|
||||||
|
|
||||||
this->seqnum = 0;
|
this->seqnum = 0;
|
||||||
|
|
|
||||||
|
|
@ -640,7 +640,8 @@ static int transport_start(struct impl *this)
|
||||||
if (this->codec_data == NULL)
|
if (this->codec_data == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
spa_log_info(this->log, "%p: using A2DP codec %s", this, this->codec->description);
|
spa_log_info(this->log, "%p: using %s codec %s", this,
|
||||||
|
this->codec->bap ? "BAP" : "A2DP", this->codec->description);
|
||||||
|
|
||||||
val = fcntl(this->transport->fd, F_GETFL);
|
val = fcntl(this->transport->fd, F_GETFL);
|
||||||
if (fcntl(this->transport->fd, F_SETFL, val | O_NONBLOCK) < 0)
|
if (fcntl(this->transport->fd, F_SETFL, val | O_NONBLOCK) < 0)
|
||||||
|
|
@ -847,7 +848,7 @@ static void emit_node_info(struct impl *this, bool full)
|
||||||
{ SPA_KEY_MEDIA_CLASS, this->is_input ? "Audio/Source" : "Stream/Output/Audio" },
|
{ SPA_KEY_MEDIA_CLASS, this->is_input ? "Audio/Source" : "Stream/Output/Audio" },
|
||||||
{ SPA_KEY_NODE_LATENCY, this->is_input ? "" : "512/48000" },
|
{ SPA_KEY_NODE_LATENCY, this->is_input ? "" : "512/48000" },
|
||||||
{ "media.name", ((this->transport && this->transport->device->name) ?
|
{ "media.name", ((this->transport && this->transport->device->name) ?
|
||||||
this->transport->device->name : "A2DP") },
|
this->transport->device->name : this->codec->bap ? "BAP" : "A2DP") },
|
||||||
{ SPA_KEY_NODE_DRIVER, this->is_input ? "true" : "false" },
|
{ SPA_KEY_NODE_DRIVER, this->is_input ? "true" : "false" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue