3924 lines
116 KiB
Diff
3924 lines
116 KiB
Diff
|
From f00d5546c9e989dd68ce0de0190cd0e043b0f1f5 Mon Sep 17 00:00:00 2001
|
||
|
From: Arjan Opmeer <arjan.opmeer@gmail.com>
|
||
|
Date: Tue, 9 Jul 2024 13:55:41 +0200
|
||
|
Subject: [PATCH 01/46] tools/btmgmt: Fix --index option for non-interactive
|
||
|
mode
|
||
|
|
||
|
In non-interactive mode the --index option does not work because the
|
||
|
call to mgmt_set_index() is made after bt_shell_attach().
|
||
|
|
||
|
Fixes: https://github.com/bluez/bluez/issues/893
|
||
|
---
|
||
|
tools/btmgmt.c | 2 +-
|
||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/tools/btmgmt.c b/tools/btmgmt.c
|
||
|
index 9b7f851bd8c6..436c2bb21f10 100644
|
||
|
--- a/tools/btmgmt.c
|
||
|
+++ b/tools/btmgmt.c
|
||
|
@@ -51,8 +51,8 @@ int main(int argc, char *argv[])
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
|
||
|
- bt_shell_attach(fileno(stdin));
|
||
|
mgmt_set_index(index_option);
|
||
|
+ bt_shell_attach(fileno(stdin));
|
||
|
status = bt_shell_run();
|
||
|
|
||
|
mgmt_remove_submenu();
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 66a76c268d05583c2396054e3f63a19c6f18bb9c Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Wed, 3 Jul 2024 17:58:39 +0300
|
||
|
Subject: [PATCH 02/46] doc: Add initial MediaAssistant rst
|
||
|
|
||
|
This adds initial documentation for the MediaAssistant D-Bus API, to
|
||
|
be used by a Broadcast Assistant application to interract with the
|
||
|
BlueZ implementation (BASS Client).
|
||
|
---
|
||
|
Makefile.am | 6 +--
|
||
|
doc/org.bluez.MediaAssistant.rst | 74 ++++++++++++++++++++++++++++++++
|
||
|
2 files changed, 77 insertions(+), 3 deletions(-)
|
||
|
create mode 100644 doc/org.bluez.MediaAssistant.rst
|
||
|
|
||
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index 0ae72111179b..46a8cfb4966f 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -362,7 +362,7 @@ man_MANS += doc/org.bluez.Adapter.5 doc/org.bluez.Device.5 \
|
||
|
man_MANS += doc/org.bluez.Media.5 doc/org.bluez.MediaControl.5 \
|
||
|
doc/org.bluez.MediaPlayer.5 doc/org.bluez.MediaFolder.5 \
|
||
|
doc/org.bluez.MediaItem.5 doc/org.bluez.MediaEndpoint.5 \
|
||
|
- doc/org.bluez.MediaTransport.5
|
||
|
+ doc/org.bluez.MediaTransport.5 doc/org.bluez.MediaAssistant.5
|
||
|
man_MANS += doc/org.bluez.GattManager.5 doc/org.bluez.GattProfile.5 \
|
||
|
doc/org.bluez.GattService.5 \
|
||
|
doc/org.bluez.GattCharacteristic.5 \
|
||
|
@@ -395,7 +395,7 @@ manual_pages += doc/org.bluez.Adapter.5 doc/org.bluez.Device.5 \
|
||
|
manual_pages += doc/org.bluez.Media.5 doc/org.bluez.MediaControl.5 \
|
||
|
doc/org.bluez.MediaPlayer.5 doc/org.bluez.MediaFolder.5 \
|
||
|
doc/org.bluez.MediaItem.5 doc/org.bluez.MediaEndpoint.5 \
|
||
|
- doc/org.bluez.MediaTransport.5
|
||
|
+ doc/org.bluez.MediaTransport.5 doc/org.bluez.MediaAssistant.5
|
||
|
manual_pages += doc/org.bluez.GattManager.5 doc/org.bluez.GattProfile.5 \
|
||
|
doc/org.bluez.GattService.5 \
|
||
|
doc/org.bluez.GattCharacteristic.5 \
|
||
|
@@ -475,7 +475,7 @@ EXTRA_DIST += doc/org.bluez.Adapter.rst doc/org.bluez.Device.rst \
|
||
|
EXTRA_DIST += doc/org.bluez.Media.rst doc/org.bluez.MediaControl.rst \
|
||
|
doc/org.bluez.MediaPlayer.rst doc/org.bluez.MediaFolder.rst \
|
||
|
doc/org.bluez.MediaItem.rst doc/org.bluez.MediaEndpoint.rst \
|
||
|
- doc/org.bluez.MediaTransport.rst
|
||
|
+ doc/org.bluez.MediaTransport.rst doc/org.bluez.MediaAssistant.rst
|
||
|
|
||
|
EXTRA_DIST += doc/org.bluez.GattManager.rst doc/org.bluez.GattProfile.rst\
|
||
|
doc/org.bluez.GattService.rst \
|
||
|
diff --git a/doc/org.bluez.MediaAssistant.rst b/doc/org.bluez.MediaAssistant.rst
|
||
|
new file mode 100644
|
||
|
index 000000000000..4aac8953619d
|
||
|
--- /dev/null
|
||
|
+++ b/doc/org.bluez.MediaAssistant.rst
|
||
|
@@ -0,0 +1,74 @@
|
||
|
+========================
|
||
|
+org.bluez.MediaAssistant
|
||
|
+========================
|
||
|
+
|
||
|
+--------------------------------------------
|
||
|
+BlueZ D-Bus MediaAssistant API documentation
|
||
|
+--------------------------------------------
|
||
|
+
|
||
|
+:Version: BlueZ
|
||
|
+:Date: June 2024
|
||
|
+:Manual section: 5
|
||
|
+:Manual group: Linux System Administration
|
||
|
+
|
||
|
+Interface
|
||
|
+=========
|
||
|
+
|
||
|
+:Service: org.bluez
|
||
|
+:Interface: org.bluez.MediaAssistant1
|
||
|
+:Object path: /org/bluez/{hci0,hci1,...}/src_XX_XX_XX_XX_XX_XX/dev_YY_YY_YY_YY_YY_YY/bisZ
|
||
|
+
|
||
|
+Methods
|
||
|
+-------
|
||
|
+
|
||
|
+void Push(dict properties)
|
||
|
+````````````````````````````````````````````````````````
|
||
|
+
|
||
|
+ Send stream information to the remote device.
|
||
|
+
|
||
|
+ :dict properties:
|
||
|
+
|
||
|
+ Indicate stream properties that will be sent to the peer.
|
||
|
+
|
||
|
+ Values:
|
||
|
+
|
||
|
+ :array{byte} Metadata [ISO only]:
|
||
|
+
|
||
|
+ See Metadata property.
|
||
|
+
|
||
|
+ :dict QoS [ISO only]:
|
||
|
+
|
||
|
+ See QoS property.
|
||
|
+
|
||
|
+Properties
|
||
|
+----------
|
||
|
+
|
||
|
+string State [readonly]
|
||
|
+```````````````````````
|
||
|
+
|
||
|
+ Indicates the state of the assistant object. Possible values are:
|
||
|
+
|
||
|
+ :"idle": assistant object was created for the stream
|
||
|
+ :"pending": assistant object was pushed (stream information was sent to the peer)
|
||
|
+ :"requesting": remote device requires Broadcast_Code
|
||
|
+ :"active": remote device started receiving stream
|
||
|
+
|
||
|
+array{byte} Metadata [readwrite, ISO Only, experimental]
|
||
|
+````````````````````````````````````````````````````````
|
||
|
+
|
||
|
+ Indicates stream Metadata.
|
||
|
+
|
||
|
+dict QoS [readwrite, ISO only, experimental]
|
||
|
+`````````````````````````````````````````````````````
|
||
|
+
|
||
|
+ Indicates stream QoS capabilities.
|
||
|
+
|
||
|
+ Values:
|
||
|
+
|
||
|
+ :byte Encryption:
|
||
|
+
|
||
|
+ Indicates whether the stream is encrypted.
|
||
|
+
|
||
|
+ :array{byte} BCode
|
||
|
+
|
||
|
+ Indicates Broadcast_Code to decrypt stream.
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 34aca9a4fbcf3d4da459f97cef4a863d7853f6e4 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?Antonio=20V=C3=A1zquez=20Blanco?=
|
||
|
<antoniovazquezblanco@gmail.com>
|
||
|
Date: Thu, 4 Jul 2024 12:11:23 +0200
|
||
|
Subject: [PATCH 03/46] bdaddr: Add cypress manufacturer support
|
||
|
|
||
|
---
|
||
|
tools/bdaddr.c | 1 +
|
||
|
1 file changed, 1 insertion(+)
|
||
|
|
||
|
diff --git a/tools/bdaddr.c b/tools/bdaddr.c
|
||
|
index bc0478d461b2..de17416e9c6c 100644
|
||
|
--- a/tools/bdaddr.c
|
||
|
+++ b/tools/bdaddr.c
|
||
|
@@ -303,6 +303,7 @@ static struct {
|
||
|
{ 48, st_write_bd_addr, generic_reset_device },
|
||
|
{ 57, ericsson_write_bd_addr, generic_reset_device },
|
||
|
{ 72, mrvl_write_bd_addr, generic_reset_device },
|
||
|
+ { 305, bcm_write_bd_addr, generic_reset_device },
|
||
|
{ 65535, NULL, NULL },
|
||
|
};
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 2748c60a2c6b1b090a7507fdd23865a598129d61 Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Tue, 9 Jul 2024 11:59:03 +0300
|
||
|
Subject: [PATCH 04/46] bap: Wait for BIG Info report event before creating
|
||
|
streams
|
||
|
|
||
|
This makes it so that stream for each BIS is created after BIG
|
||
|
Info report is received. This ensures that when the stream is
|
||
|
created the encryption field is correctly set.
|
||
|
---
|
||
|
profiles/audio/bap.c | 27 ++++++++++++++++++++++++---
|
||
|
1 file changed, 24 insertions(+), 3 deletions(-)
|
||
|
|
||
|
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
|
||
|
index e82a253825f1..afa938091996 100644
|
||
|
--- a/profiles/audio/bap.c
|
||
|
+++ b/profiles/audio/bap.c
|
||
|
@@ -134,6 +134,7 @@ struct bap_bcast_pa_req {
|
||
|
struct btd_service *service;
|
||
|
struct bap_setup *setup;
|
||
|
} data;
|
||
|
+ unsigned int io_id; /* io_id for BIG Info watch */
|
||
|
};
|
||
|
|
||
|
static struct queue *sessions;
|
||
|
@@ -1220,7 +1221,8 @@ fail:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
|
||
|
+static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond,
|
||
|
+ gpointer user_data)
|
||
|
{
|
||
|
GError *err = NULL;
|
||
|
struct bap_bcast_pa_req *req = user_data;
|
||
|
@@ -1228,7 +1230,7 @@ static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
|
||
|
struct bt_iso_base base;
|
||
|
struct bt_iso_qos qos;
|
||
|
|
||
|
- DBG("PA Sync done");
|
||
|
+ DBG("BIG Info received");
|
||
|
|
||
|
bt_io_get(io, &err,
|
||
|
BT_IO_OPT_BASE, &base,
|
||
|
@@ -1238,7 +1240,8 @@ static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
|
||
|
error("%s", err->message);
|
||
|
g_error_free(err);
|
||
|
g_io_channel_shutdown(io, TRUE, NULL);
|
||
|
- return;
|
||
|
+ req->io_id = 0;
|
||
|
+ return FALSE;
|
||
|
}
|
||
|
|
||
|
/* Close the io and remove the queue request for another PA Sync */
|
||
|
@@ -1255,7 +1258,21 @@ static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
|
||
|
service_set_connecting(req->data.service);
|
||
|
|
||
|
queue_remove(data->adapter->bcast_pa_requests, req);
|
||
|
+ req->io_id = 0;
|
||
|
free(req);
|
||
|
+
|
||
|
+ return FALSE;
|
||
|
+}
|
||
|
+
|
||
|
+static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
|
||
|
+{
|
||
|
+ struct bap_bcast_pa_req *req = user_data;
|
||
|
+ /* PA Sync was established, wait for BIG Info report so that the
|
||
|
+ * encryption flag is also available.
|
||
|
+ */
|
||
|
+ DBG("PA Sync done");
|
||
|
+ req->io_id = g_io_add_watch(io, G_IO_OUT, big_info_report_cb,
|
||
|
+ user_data);
|
||
|
}
|
||
|
|
||
|
static bool match_data_bap_data(const void *data, const void *match_data)
|
||
|
@@ -3177,6 +3194,10 @@ static void bap_bcast_remove(struct btd_service *service)
|
||
|
*/
|
||
|
req = queue_remove_if(data->adapter->bcast_pa_requests,
|
||
|
match_service, service);
|
||
|
+ if (req->io_id) {
|
||
|
+ g_source_remove(req->io_id);
|
||
|
+ req->io_id = 0;
|
||
|
+ }
|
||
|
free(req);
|
||
|
|
||
|
bap_data_remove(data);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From aa6063aa66954ac8321211145d1ae6b434b2555c Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Tue, 9 Jul 2024 17:35:00 +0300
|
||
|
Subject: [PATCH 05/46] health: mcap: add checks for NULL mcap_notify_error()
|
||
|
|
||
|
It is necessary to prevent dereferencing of NULL pointers.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
profiles/health/mcap.c | 9 +++++++++
|
||
|
1 file changed, 9 insertions(+)
|
||
|
|
||
|
diff --git a/profiles/health/mcap.c b/profiles/health/mcap.c
|
||
|
index 7eceaa88a3a9..2e4214a6984f 100644
|
||
|
--- a/profiles/health/mcap.c
|
||
|
+++ b/profiles/health/mcap.c
|
||
|
@@ -336,6 +336,9 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
|
||
|
case MCAP_MD_CREATE_MDL_REQ:
|
||
|
st = MDL_WAITING;
|
||
|
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
|
||
|
+ if (!l)
|
||
|
+ return;
|
||
|
+
|
||
|
mdl = l->data;
|
||
|
mcl->mdls = g_slist_remove(mcl->mdls, mdl);
|
||
|
mcap_mdl_unref(mdl);
|
||
|
@@ -345,6 +348,9 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
|
||
|
case MCAP_MD_ABORT_MDL_REQ:
|
||
|
st = MDL_WAITING;
|
||
|
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
|
||
|
+ if (!l)
|
||
|
+ return;
|
||
|
+
|
||
|
shutdown_mdl(l->data);
|
||
|
update_mcl_state(mcl);
|
||
|
con->cb.notify(err, con->user_data);
|
||
|
@@ -362,6 +368,9 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
|
||
|
case MCAP_MD_RECONNECT_MDL_REQ:
|
||
|
st = MDL_WAITING;
|
||
|
l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state);
|
||
|
+ if (!l)
|
||
|
+ return;
|
||
|
+
|
||
|
shutdown_mdl(l->data);
|
||
|
update_mcl_state(mcl);
|
||
|
con->cb.op(NULL, err, con->user_data);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 11dcc9bf0dba61c83269fb3cf234579d6f9ef192 Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Tue, 9 Jul 2024 17:35:01 +0300
|
||
|
Subject: [PATCH 06/46] shared: prevent dereferencing of NULL pointers
|
||
|
|
||
|
It is necessary to add checks for NULL before dereferencing pointers.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
src/shared/micp.c | 4 ++++
|
||
|
src/shared/vcp.c | 12 ++++++++++++
|
||
|
2 files changed, 16 insertions(+)
|
||
|
|
||
|
diff --git a/src/shared/micp.c b/src/shared/micp.c
|
||
|
index b82bd92dedb8..1c34e9d0079f 100644
|
||
|
--- a/src/shared/micp.c
|
||
|
+++ b/src/shared/micp.c
|
||
|
@@ -398,6 +398,10 @@ static void mics_mute_write(struct gatt_db_attribute *attrib,
|
||
|
}
|
||
|
|
||
|
micp_op = iov_pull_mem(&iov, sizeof(*micp_op));
|
||
|
+ if (!micp_op) {
|
||
|
+ DBG(micp, "iov_pull_mem() returned NULL");
|
||
|
+ goto respond;
|
||
|
+ }
|
||
|
|
||
|
if ((*micp_op == MICS_DISABLED) || (*micp_op != MICS_NOT_MUTED
|
||
|
&& *micp_op != MICS_MUTED)) {
|
||
|
diff --git a/src/shared/vcp.c b/src/shared/vcp.c
|
||
|
index 06264a24146c..602d46dc1d1d 100644
|
||
|
--- a/src/shared/vcp.c
|
||
|
+++ b/src/shared/vcp.c
|
||
|
@@ -925,6 +925,10 @@ static void vcs_cp_write(struct gatt_db_attribute *attrib,
|
||
|
}
|
||
|
|
||
|
vcp_op = iov_pull_mem(&iov, sizeof(*vcp_op));
|
||
|
+ if (!vcp_op) {
|
||
|
+ DBG(vcp, "iov_pull_mem() returned NULL");
|
||
|
+ goto respond;
|
||
|
+ }
|
||
|
|
||
|
for (handler = vcp_handlers; handler && handler->str; handler++) {
|
||
|
if (handler->op != *vcp_op)
|
||
|
@@ -985,6 +989,10 @@ static void vocs_cp_write(struct gatt_db_attribute *attrib,
|
||
|
}
|
||
|
|
||
|
vcp_op = iov_pull_mem(&iov, sizeof(*vcp_op));
|
||
|
+ if (!vcp_op) {
|
||
|
+ DBG(vcp, "iov_pull_mem() returned NULL");
|
||
|
+ goto respond;
|
||
|
+ }
|
||
|
|
||
|
for (handler = vocp_handlers; handler && handler->str; handler++) {
|
||
|
if (handler->op != *vcp_op)
|
||
|
@@ -1517,6 +1525,10 @@ static void aics_ip_cp_write(struct gatt_db_attribute *attrib,
|
||
|
}
|
||
|
|
||
|
aics_op = iov_pull_mem(&iov, sizeof(*aics_op));
|
||
|
+ if (!aics_op) {
|
||
|
+ DBG(vcp, "iov_pull_mem() returned NULL");
|
||
|
+ goto respond;
|
||
|
+ }
|
||
|
|
||
|
for (handler = aics_handlers; handler && handler->str; handler++) {
|
||
|
if (handler->op != *aics_op)
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 755091581336dd6b6a710e599da9e1e52037851a Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Tue, 9 Jul 2024 17:35:02 +0300
|
||
|
Subject: [PATCH 07/46] settings: limit string size in load_service()
|
||
|
|
||
|
It is necessary to prevent buffer overflow by limiting
|
||
|
the maximum string length.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
src/settings.c | 2 +-
|
||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/src/settings.c b/src/settings.c
|
||
|
index b61e694f1b85..643a083dbc84 100644
|
||
|
--- a/src/settings.c
|
||
|
+++ b/src/settings.c
|
||
|
@@ -193,7 +193,7 @@ static int load_service(struct gatt_db *db, char *handle, char *value)
|
||
|
return -EIO;
|
||
|
}
|
||
|
|
||
|
- if (sscanf(value, "%[^:]:%04hx:%36s", type, &end, uuid_str) != 3) {
|
||
|
+ if (sscanf(value, "%36[^:]:%04hx:%36s", type, &end, uuid_str) != 3) {
|
||
|
DBG("Failed to parse value: %s", value);
|
||
|
return -EIO;
|
||
|
}
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 4ca662fcea1604e937bde1bddd5de2c50bcb6e00 Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Tue, 9 Jul 2024 17:35:03 +0300
|
||
|
Subject: [PATCH 08/46] settings: limit string size in gatt_db_load()
|
||
|
|
||
|
It is necessary to prevent buffer overflow by limiting
|
||
|
the maximum string length.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
src/settings.c | 4 ++--
|
||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/src/settings.c b/src/settings.c
|
||
|
index 643a083dbc84..37164939573f 100644
|
||
|
--- a/src/settings.c
|
||
|
+++ b/src/settings.c
|
||
|
@@ -232,7 +232,7 @@ static int gatt_db_load(struct gatt_db *db, GKeyFile *key_file, char **keys)
|
||
|
value = g_key_file_get_string(key_file, "Attributes", *handle,
|
||
|
NULL);
|
||
|
|
||
|
- if (!value || sscanf(value, "%[^:]:", type) != 1) {
|
||
|
+ if (!value || sscanf(value, "%36[^:]:", type) != 1) {
|
||
|
g_free(value);
|
||
|
return -EIO;
|
||
|
}
|
||
|
@@ -255,7 +255,7 @@ static int gatt_db_load(struct gatt_db *db, GKeyFile *key_file, char **keys)
|
||
|
value = g_key_file_get_string(key_file, "Attributes", *handle,
|
||
|
NULL);
|
||
|
|
||
|
- if (!value || sscanf(value, "%[^:]:", type) != 1) {
|
||
|
+ if (!value || sscanf(value, "%36[^:]:", type) != 1) {
|
||
|
g_free(value);
|
||
|
return -EIO;
|
||
|
}
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From e56fc72fc66765f407473e4cb903fdc80784a4ff Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Wed, 10 Jul 2024 14:31:44 +0300
|
||
|
Subject: [PATCH 09/46] gatt: add return value check of io_get_fd() to
|
||
|
sock_io_send()
|
||
|
|
||
|
It is necessary to add a return value check.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
src/gatt-database.c | 9 ++++++++-
|
||
|
1 file changed, 8 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/src/gatt-database.c b/src/gatt-database.c
|
||
|
index 8472aac5941d..6c84b085ca29 100644
|
||
|
--- a/src/gatt-database.c
|
||
|
+++ b/src/gatt-database.c
|
||
|
@@ -2630,6 +2630,7 @@ static int sock_io_send(struct io *io, const void *data, size_t len)
|
||
|
{
|
||
|
struct msghdr msg;
|
||
|
struct iovec iov;
|
||
|
+ int fd;
|
||
|
|
||
|
iov.iov_base = (void *) data;
|
||
|
iov.iov_len = len;
|
||
|
@@ -2638,7 +2639,13 @@ static int sock_io_send(struct io *io, const void *data, size_t len)
|
||
|
msg.msg_iov = &iov;
|
||
|
msg.msg_iovlen = 1;
|
||
|
|
||
|
- return sendmsg(io_get_fd(io), &msg, MSG_NOSIGNAL);
|
||
|
+ fd = io_get_fd(io);
|
||
|
+ if (fd < 0) {
|
||
|
+ error("io_get_fd() returned %d\n", fd);
|
||
|
+ return fd;
|
||
|
+ }
|
||
|
+
|
||
|
+ return sendmsg(fd, &msg, MSG_NOSIGNAL);
|
||
|
}
|
||
|
|
||
|
static void att_disconnect_cb(int err, void *user_data)
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From ba70a116d97108f21a853f5549758a720fdbefb3 Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Wed, 10 Jul 2024 14:31:45 +0300
|
||
|
Subject: [PATCH 10/46] shared/vcp: add NULL checks to foreach_aics_service()
|
||
|
|
||
|
Make foreach_aics_service() safe for passing NULL pointers.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
src/shared/vcp.c | 3 +++
|
||
|
1 file changed, 3 insertions(+)
|
||
|
|
||
|
diff --git a/src/shared/vcp.c b/src/shared/vcp.c
|
||
|
index 602d46dc1d1d..43ef1d18644d 100644
|
||
|
--- a/src/shared/vcp.c
|
||
|
+++ b/src/shared/vcp.c
|
||
|
@@ -2729,6 +2729,9 @@ static void foreach_aics_service(struct gatt_db_attribute *attr,
|
||
|
struct bt_vcp *vcp = user_data;
|
||
|
struct bt_aics *aics = vcp_get_aics(vcp);
|
||
|
|
||
|
+ if (!aics || !attr)
|
||
|
+ return;
|
||
|
+
|
||
|
aics->service = attr;
|
||
|
|
||
|
gatt_db_service_set_claimed(attr, true);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 12525371ef082483d524447310da7d0f5866bf91 Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Wed, 10 Jul 2024 14:31:46 +0300
|
||
|
Subject: [PATCH 11/46] client/player: add error code handling to
|
||
|
transport_recv()
|
||
|
|
||
|
It is necessary to add return value check as in sock_send().
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
client/player.c | 8 +++++++-
|
||
|
1 file changed, 7 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index 584fc5e8148a..de4491b534c2 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -4514,7 +4514,13 @@ static bool transport_recv(struct io *io, void *user_data)
|
||
|
uint8_t buf[1024];
|
||
|
int ret, len;
|
||
|
|
||
|
- ret = read(io_get_fd(io), buf, sizeof(buf));
|
||
|
+ ret = io_get_fd(io);
|
||
|
+ if (ret < 0) {
|
||
|
+ bt_shell_printf("io_get_fd() returned %d\n", ret);
|
||
|
+ return true;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = read(ret, buf, sizeof(buf));
|
||
|
if (ret < 0) {
|
||
|
bt_shell_printf("Failed to read: %s (%d)\n", strerror(errno),
|
||
|
-errno);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 7ffc08dd78d68eff15bb77e43efbc1b606fb4fd8 Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Wed, 10 Jul 2024 14:31:47 +0300
|
||
|
Subject: [PATCH 12/46] shared/vcp: prevent dereferencing of NULL pointers
|
||
|
|
||
|
util_memdup() will terminate the program if memory
|
||
|
allocation fails.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
src/shared/vcp.c | 20 ++++----------------
|
||
|
1 file changed, 4 insertions(+), 16 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/vcp.c b/src/shared/vcp.c
|
||
|
index 43ef1d18644d..cfc426624875 100644
|
||
|
--- a/src/shared/vcp.c
|
||
|
+++ b/src/shared/vcp.c
|
||
|
@@ -2139,14 +2139,8 @@ static void read_vocs_audio_descriptor(struct bt_vcp *vcp, bool success,
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
- vocs_ao_dec_r = malloc(length+1);
|
||
|
- memset(vocs_ao_dec_r, 0, length+1);
|
||
|
- memcpy(vocs_ao_dec_r, value, length);
|
||
|
-
|
||
|
- if (!vocs_ao_dec_r) {
|
||
|
- DBG(vcp, "Unable to get VOCS Audio Descriptor");
|
||
|
- return;
|
||
|
- }
|
||
|
+ vocs_ao_dec_r = util_memdup(value, length + 1);
|
||
|
+ memset(vocs_ao_dec_r + length, 0, 1);
|
||
|
|
||
|
DBG(vcp, "VOCS Audio Descriptor: %s", vocs_ao_dec_r);
|
||
|
free(vocs_ao_dec_r);
|
||
|
@@ -2543,14 +2537,8 @@ static void read_aics_audio_ip_description(struct bt_vcp *vcp, bool success,
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
- ip_descrptn = malloc(length+1);
|
||
|
- memset(ip_descrptn, 0, length+1);
|
||
|
- memcpy(ip_descrptn, value, length);
|
||
|
-
|
||
|
- if (!ip_descrptn) {
|
||
|
- DBG(vcp, "Unable to get Audio Input Description");
|
||
|
- return;
|
||
|
- }
|
||
|
+ ip_descrptn = util_memdup(value, length + 1);
|
||
|
+ memset(ip_descrptn + length, 0, 1);
|
||
|
|
||
|
DBG(vcp, "Audio Input Description: %s", ip_descrptn);
|
||
|
free(ip_descrptn);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From cf3d80a01f1f21538148cb9a5569b678dad0848b Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Wed, 10 Jul 2024 14:31:48 +0300
|
||
|
Subject: [PATCH 13/46] client/player: fix the order of args in
|
||
|
cmd_register_endpoint()
|
||
|
|
||
|
Based on the function prototype, ep->cid and ep->vid should be swapped.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
client/player.c | 2 +-
|
||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index de4491b534c2..2480ed64b8e5 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -3388,7 +3388,7 @@ static void cmd_register_endpoint(int argc, char *argv[])
|
||
|
|
||
|
if (strrchr(argv[2], ':')) {
|
||
|
ep->codec = 0xff;
|
||
|
- parse_vendor_codec(argv[2], &ep->cid, &ep->vid);
|
||
|
+ parse_vendor_codec(argv[2], &ep->vid, &ep->cid);
|
||
|
ep->preset = new0(struct preset, 1);
|
||
|
ep->preset->custom.name = strdup("custom");
|
||
|
ep->preset->default_preset = &ep->preset->custom;
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 7a45038dc1e505afbaa49f8dd64fd41dab627f23 Mon Sep 17 00:00:00 2001
|
||
|
From: Roman Smirnov <r.smirnov@omp.ru>
|
||
|
Date: Wed, 10 Jul 2024 14:31:49 +0300
|
||
|
Subject: [PATCH 14/46] shared/gatt-client: add NULL check to
|
||
|
discover_secondary_cb()
|
||
|
|
||
|
It is necessary to prevent dereferencing of a NULL pointer.
|
||
|
|
||
|
Found with the SVACE static analysis tool.
|
||
|
---
|
||
|
src/shared/gatt-client.c | 4 +++-
|
||
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
|
||
|
index b48d739fc609..9db3f52117ff 100644
|
||
|
--- a/src/shared/gatt-client.c
|
||
|
+++ b/src/shared/gatt-client.c
|
||
|
@@ -1276,7 +1276,9 @@ next:
|
||
|
|
||
|
range = queue_peek_head(op->discov_ranges);
|
||
|
|
||
|
- client->discovery_req = bt_gatt_discover_included_services(client->att,
|
||
|
+ if (range)
|
||
|
+ client->discovery_req = bt_gatt_discover_included_services(
|
||
|
+ client->att,
|
||
|
range->start,
|
||
|
range->end,
|
||
|
discover_incl_cb,
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 9cc587947b6ac56a4c94dcc880b273bc72af22a8 Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Thu, 11 Jul 2024 15:11:56 -0400
|
||
|
Subject: [PATCH 15/46] device: Fix overwritting current_flags
|
||
|
|
||
|
MGMT Set Device Flags overwrites the current_flags so only the last
|
||
|
flags set this way would remain active which can be seem in the
|
||
|
following sequence when LL Privacy is enabled:
|
||
|
|
||
|
@ MGMT Command: Set Device Flags (0x0050) plen 11
|
||
|
LE Address: CF:AC:A6:79:3D:B9 (Static)
|
||
|
Current Flags: 0x00000001
|
||
|
Remote Wakeup
|
||
|
@ MGMT Event: Command Complete (0x0001) plen 10
|
||
|
Set Device Flags (0x0050) plen 7
|
||
|
Status: Success (0x00)
|
||
|
LE Address: CF:AC:A6:79:3D:B9 (Static)
|
||
|
@ MGMT Command: Set Device Flags (0x0050) plen 11
|
||
|
LE Address: CF:AC:A6:79:3D:B9 (Static)
|
||
|
Current Flags: 0x00000002
|
||
|
Device Privacy Mode
|
||
|
@ MGMT Event: Command Complete (0x0001) plen 10
|
||
|
Set Device Flags (0x0050) plen 7
|
||
|
Status: Success (0x00)
|
||
|
LE Address: CF:AC:A6:79:3D:B9 (Static)
|
||
|
|
||
|
In order to do this properly the code needs to track the pending_flags
|
||
|
being set and also call btd_device_flags_changed whenever a change is
|
||
|
complete since that event is not generated when MGMT_OP_SET_DEVICE_FLAGS
|
||
|
is sent by bluetoothd itself.
|
||
|
---
|
||
|
src/adapter.c | 20 +++++++++++++++++---
|
||
|
src/device.c | 20 +++++++++++++++++++-
|
||
|
src/device.h | 2 ++
|
||
|
3 files changed, 38 insertions(+), 4 deletions(-)
|
||
|
|
||
|
diff --git a/src/adapter.c b/src/adapter.c
|
||
|
index bb49a1ecad23..85ddfc16568f 100644
|
||
|
--- a/src/adapter.c
|
||
|
+++ b/src/adapter.c
|
||
|
@@ -5569,6 +5569,7 @@ void adapter_accept_list_remove(struct btd_adapter *adapter,
|
||
|
static void set_device_privacy_complete(uint8_t status, uint16_t length,
|
||
|
const void *param, void *user_data)
|
||
|
{
|
||
|
+ struct btd_device *dev = user_data;
|
||
|
const struct mgmt_rp_set_device_flags *rp = param;
|
||
|
|
||
|
if (status != MGMT_STATUS_SUCCESS) {
|
||
|
@@ -5581,6 +5582,9 @@ static void set_device_privacy_complete(uint8_t status, uint16_t length,
|
||
|
error("Too small Set Device Flags complete event: %d", length);
|
||
|
return;
|
||
|
}
|
||
|
+
|
||
|
+ btd_device_flags_changed(dev, btd_device_get_supported_flags(dev),
|
||
|
+ btd_device_get_pending_flags(dev));
|
||
|
}
|
||
|
|
||
|
static void add_device_complete(uint8_t status, uint16_t length,
|
||
|
@@ -5626,7 +5630,7 @@ static void add_device_complete(uint8_t status, uint16_t length,
|
||
|
adapter_set_device_flags(adapter, dev, flags |
|
||
|
DEVICE_FLAG_DEVICE_PRIVACY,
|
||
|
set_device_privacy_complete,
|
||
|
- NULL);
|
||
|
+ dev);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
@@ -5676,6 +5680,7 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
|
||
|
{
|
||
|
struct mgmt_cp_set_device_flags cp;
|
||
|
uint32_t supported = btd_device_get_supported_flags(device);
|
||
|
+ uint32_t pending = btd_device_get_pending_flags(device);
|
||
|
const bdaddr_t *bdaddr;
|
||
|
uint8_t bdaddr_type;
|
||
|
|
||
|
@@ -5683,6 +5688,14 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
|
||
|
(supported | flags) != supported)
|
||
|
return;
|
||
|
|
||
|
+ /* Check if changing flags are pending */
|
||
|
+ if (flags == (flags & pending))
|
||
|
+ return;
|
||
|
+
|
||
|
+ /* Set Device Privacy Mode if it has not set the flag yet. */
|
||
|
+ if (btd_opts.device_privacy && !(flags & DEVICE_FLAG_DEVICE_PRIVACY))
|
||
|
+ flags |= DEVICE_FLAG_DEVICE_PRIVACY & supported & ~pending;
|
||
|
+
|
||
|
bdaddr = device_get_address(device);
|
||
|
bdaddr_type = btd_device_get_bdaddr_type(device);
|
||
|
|
||
|
@@ -5691,8 +5704,9 @@ void adapter_set_device_flags(struct btd_adapter *adapter,
|
||
|
cp.addr.type = bdaddr_type;
|
||
|
cp.current_flags = cpu_to_le32(flags);
|
||
|
|
||
|
- mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
|
||
|
- sizeof(cp), &cp, func, user_data, NULL);
|
||
|
+ if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id,
|
||
|
+ sizeof(cp), &cp, func, user_data, NULL))
|
||
|
+ btd_device_set_pending_flags(device, flags);
|
||
|
}
|
||
|
|
||
|
static void device_flags_changed_callback(uint16_t index, uint16_t length,
|
||
|
diff --git a/src/device.c b/src/device.c
|
||
|
index 097b1fbba37d..a1dc0750ca41 100644
|
||
|
--- a/src/device.c
|
||
|
+++ b/src/device.c
|
||
|
@@ -214,6 +214,7 @@ struct btd_device {
|
||
|
GDBusPendingPropertySet wake_id;
|
||
|
|
||
|
uint32_t supported_flags;
|
||
|
+ uint32_t pending_flags;
|
||
|
uint32_t current_flags;
|
||
|
GSList *svc_callbacks;
|
||
|
GSList *eir_uuids;
|
||
|
@@ -1569,7 +1570,7 @@ static void set_wake_allowed_complete(uint8_t status, uint16_t length,
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
- device_set_wake_allowed_complete(dev);
|
||
|
+ btd_device_flags_changed(dev, dev->supported_flags, dev->pending_flags);
|
||
|
}
|
||
|
|
||
|
void device_set_wake_allowed(struct btd_device *device, bool wake_allowed,
|
||
|
@@ -7243,6 +7244,22 @@ uint32_t btd_device_get_supported_flags(struct btd_device *dev)
|
||
|
return dev->supported_flags;
|
||
|
}
|
||
|
|
||
|
+void btd_device_set_pending_flags(struct btd_device *dev, uint32_t flags)
|
||
|
+{
|
||
|
+ if (!dev)
|
||
|
+ return;
|
||
|
+
|
||
|
+ dev->pending_flags = flags;
|
||
|
+}
|
||
|
+
|
||
|
+uint32_t btd_device_get_pending_flags(struct btd_device *dev)
|
||
|
+{
|
||
|
+ if (!dev)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ return dev->pending_flags;
|
||
|
+}
|
||
|
+
|
||
|
/* This event is sent immediately after add device on all mgmt sockets.
|
||
|
* Afterwards, it is only sent to mgmt sockets other than the one which called
|
||
|
* set_device_flags.
|
||
|
@@ -7255,6 +7272,7 @@ void btd_device_flags_changed(struct btd_device *dev, uint32_t supported_flags,
|
||
|
|
||
|
dev->supported_flags = supported_flags;
|
||
|
dev->current_flags = current_flags;
|
||
|
+ dev->pending_flags = 0;
|
||
|
|
||
|
if (!changed_flags)
|
||
|
return;
|
||
|
diff --git a/src/device.h b/src/device.h
|
||
|
index 0794f92d0178..3742f6028040 100644
|
||
|
--- a/src/device.h
|
||
|
+++ b/src/device.h
|
||
|
@@ -191,6 +191,8 @@ int btd_device_connect_services(struct btd_device *dev, GSList *services);
|
||
|
|
||
|
uint32_t btd_device_get_current_flags(struct btd_device *dev);
|
||
|
uint32_t btd_device_get_supported_flags(struct btd_device *dev);
|
||
|
+uint32_t btd_device_get_pending_flags(struct btd_device *dev);
|
||
|
+void btd_device_set_pending_flags(struct btd_device *dev, uint32_t flags);
|
||
|
void btd_device_flags_changed(struct btd_device *dev, uint32_t supported_flags,
|
||
|
uint32_t current_flags);
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 73266377b0185c56c921b8cece257df428612d73 Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Fri, 12 Jul 2024 15:27:12 -0400
|
||
|
Subject: [PATCH 16/46] shared/bap: Fix ASE notification order
|
||
|
|
||
|
When processing a CP operation the CP shall be notified ahead of
|
||
|
the ASE itself:
|
||
|
|
||
|
'If the server successfully completes a client-initiated ASE Control
|
||
|
operation for an ASE, the server shall send a notification of the ASE
|
||
|
Control Point characteristic value formatted as defined in Table 4.7.
|
||
|
The server shall then perform the behavior defined in Section 5.1
|
||
|
through Section 5.8 for that ASE Control operation and send
|
||
|
notifications of any ASE characteristic values written during that
|
||
|
ASE Control operation.'
|
||
|
|
||
|
So this delays the processing of notifications of ASE states so the CP
|
||
|
responses always appears first in the notification e.g:
|
||
|
|
||
|
> ACL Data RX: Handle 42 flags 0x02 dlen 59
|
||
|
ATT: Handle Multiple Value Notification (0x23) len 54
|
||
|
Length: 0x0008
|
||
|
Handle: 0x0036 Type: ASE Control Point (0x2bc6)
|
||
|
Data[8]: 0202030000010000
|
||
|
Opcode: QoS Configuration (0x02)
|
||
|
Number of ASE(s): 2
|
||
|
ASE: #0
|
||
|
ASE ID: 0x03
|
||
|
ASE Response Code: Success (0x00)
|
||
|
ASE Response Reason: None (0x00)
|
||
|
ASE: #1
|
||
|
ASE ID: 0x01
|
||
|
ASE Response Code: Success (0x00)
|
||
|
ASE Response Reason: None (0x00)
|
||
|
Length: 0x0011
|
||
|
Handle: 0x0030 Type: Source ASE (0x2bc5)
|
||
|
Data[17]: 0302000010270000022800020a00409c00
|
||
|
ASE ID: 3
|
||
|
State: QoS Configured (0x02)
|
||
|
CIG ID: 0x00
|
||
|
CIS ID: 0x00
|
||
|
SDU Interval: 10000 usec
|
||
|
Framing: Unframed (0x00)
|
||
|
PHY: 0x02
|
||
|
LE 2M PHY (0x02)
|
||
|
Max SDU: 40
|
||
|
RTN: 2
|
||
|
Max Transport Latency: 10
|
||
|
Presentation Delay: 40000 us
|
||
|
Length: 0x0011
|
||
|
Handle: 0x002a Type: Sink ASE (0x2bc4)
|
||
|
Data[17]: 0102000010270000025000020a00409c00
|
||
|
ASE ID: 1
|
||
|
State: QoS Configured (0x02)
|
||
|
CIG ID: 0x00
|
||
|
CIS ID: 0x00
|
||
|
SDU Interval: 10000 usec
|
||
|
Framing: Unframed (0x00)
|
||
|
PHY: 0x02
|
||
|
LE 2M PHY (0x02)
|
||
|
Max SDU: 80
|
||
|
RTN: 2
|
||
|
Max Transport Latency: 10
|
||
|
Presentation Delay: 40000 us
|
||
|
---
|
||
|
src/shared/bap.c | 53 +++++++++++++++++++++++++++++++++++++++---------
|
||
|
1 file changed, 43 insertions(+), 10 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index 3a4c1f9d3a98..d59eac8cca16 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -169,6 +169,7 @@ struct bt_bap {
|
||
|
unsigned int process_id;
|
||
|
unsigned int disconn_id;
|
||
|
unsigned int idle_id;
|
||
|
+ bool in_cp_write;
|
||
|
|
||
|
struct queue *reqs;
|
||
|
struct queue *notify;
|
||
|
@@ -266,6 +267,7 @@ struct bt_bap_stream {
|
||
|
const struct bt_bap_stream_ops *ops;
|
||
|
uint8_t old_state;
|
||
|
uint8_t state;
|
||
|
+ unsigned int state_id;
|
||
|
bool client;
|
||
|
void *user_data;
|
||
|
};
|
||
|
@@ -1102,6 +1104,8 @@ static void bap_stream_free(void *data)
|
||
|
{
|
||
|
struct bt_bap_stream *stream = data;
|
||
|
|
||
|
+ timeout_remove(stream->state_id);
|
||
|
+
|
||
|
if (stream->ep)
|
||
|
stream->ep->stream = NULL;
|
||
|
|
||
|
@@ -1579,20 +1583,17 @@ static bool bap_queue_req(struct bt_bap *bap, struct bt_bap_req *req)
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
-static void bap_ucast_set_state(struct bt_bap_stream *stream, uint8_t state)
|
||
|
+static bool stream_notify_state(void *data)
|
||
|
{
|
||
|
+ struct bt_bap_stream *stream = data;
|
||
|
struct bt_bap_endpoint *ep = stream->ep;
|
||
|
|
||
|
- ep->old_state = ep->state;
|
||
|
- ep->state = state;
|
||
|
-
|
||
|
- DBG(stream->bap, "stream %p dir 0x%02x: %s -> %s", stream,
|
||
|
- bt_bap_stream_get_dir(stream),
|
||
|
- bt_bap_stream_statestr(stream->ep->old_state),
|
||
|
- bt_bap_stream_statestr(stream->ep->state));
|
||
|
+ DBG(stream->bap, "stream %p", stream);
|
||
|
|
||
|
- if (stream->lpac->type == BT_BAP_BCAST_SINK || stream->client)
|
||
|
- goto done;
|
||
|
+ if (stream->state_id) {
|
||
|
+ timeout_remove(stream->state_id);
|
||
|
+ stream->state_id = 0;
|
||
|
+ }
|
||
|
|
||
|
switch (ep->state) {
|
||
|
case BT_ASCS_ASE_STATE_IDLE:
|
||
|
@@ -1610,6 +1611,31 @@ static void bap_ucast_set_state(struct bt_bap_stream *stream, uint8_t state)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
+ return false;
|
||
|
+}
|
||
|
+
|
||
|
+static void bap_ucast_set_state(struct bt_bap_stream *stream, uint8_t state)
|
||
|
+{
|
||
|
+ struct bt_bap_endpoint *ep = stream->ep;
|
||
|
+
|
||
|
+ ep->old_state = ep->state;
|
||
|
+ ep->state = state;
|
||
|
+
|
||
|
+ DBG(stream->bap, "stream %p dir 0x%02x: %s -> %s", stream,
|
||
|
+ bt_bap_stream_get_dir(stream),
|
||
|
+ bt_bap_stream_statestr(stream->ep->old_state),
|
||
|
+ bt_bap_stream_statestr(stream->ep->state));
|
||
|
+
|
||
|
+ if (stream->client)
|
||
|
+ goto done;
|
||
|
+
|
||
|
+ if (!stream->bap->in_cp_write)
|
||
|
+ stream_notify_state(stream);
|
||
|
+ else if (!stream->state_id)
|
||
|
+ stream->state_id = timeout_add(BAP_PROCESS_TIMEOUT,
|
||
|
+ stream_notify_state,
|
||
|
+ stream, NULL);
|
||
|
+
|
||
|
done:
|
||
|
bap_stream_state_changed(stream);
|
||
|
}
|
||
|
@@ -3069,8 +3095,15 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
|
||
|
|
||
|
DBG(bap, "%s", handler->str);
|
||
|
|
||
|
+ /* Set in_cp_write so ASE notification are not sent ahead of
|
||
|
+ * CP notifcation.
|
||
|
+ */
|
||
|
+ bap->in_cp_write = true;
|
||
|
+
|
||
|
for (i = 0; i < hdr->num; i++)
|
||
|
ret = handler->func(ascs, bap, &iov, rsp);
|
||
|
+
|
||
|
+ bap->in_cp_write = false;
|
||
|
} else {
|
||
|
DBG(bap, "Unknown opcode 0x%02x", hdr->op);
|
||
|
ascs_ase_rsp_add_errno(rsp, 0x00, -ENOTSUP);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 025f07ec0d0ebfb5e83c07d2918a6c01b0ae49a6 Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Fri, 12 Jul 2024 10:52:03 -0400
|
||
|
Subject: [PATCH 17/46] client/player: Add support for name custom presets
|
||
|
|
||
|
This adds support for naming custom presets instead of always having
|
||
|
just one "custom" codec preset which needs to be overwriten everytime
|
||
|
a new set of settings needs to be entered.
|
||
|
---
|
||
|
client/player.c | 130 ++++++++++++++++++++++++++++++++----------------
|
||
|
1 file changed, 87 insertions(+), 43 deletions(-)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index 2480ed64b8e5..26190fef7bc1 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -1232,6 +1232,7 @@ struct codec_preset {
|
||
|
const struct iovec data;
|
||
|
struct bt_bap_qos qos;
|
||
|
uint8_t target_latency;
|
||
|
+ bool custom;
|
||
|
};
|
||
|
|
||
|
#define SBC_PRESET(_name, _data) \
|
||
|
@@ -1448,7 +1449,6 @@ static void print_lc3_meta(void *data, int len)
|
||
|
{ \
|
||
|
.uuid = _uuid, \
|
||
|
.codec = _codec, \
|
||
|
- .custom = { .name = "custom" }, \
|
||
|
.default_preset = &_presets[_default_index], \
|
||
|
.presets = _presets, \
|
||
|
.num_presets = ARRAY_SIZE(_presets), \
|
||
|
@@ -1459,7 +1459,7 @@ static struct preset {
|
||
|
uint8_t codec;
|
||
|
uint16_t cid;
|
||
|
uint16_t vid;
|
||
|
- struct codec_preset custom;
|
||
|
+ struct queue *custom;
|
||
|
struct codec_preset *default_preset;
|
||
|
struct codec_preset *presets;
|
||
|
size_t num_presets;
|
||
|
@@ -1557,6 +1557,14 @@ static struct preset *find_presets_name(const char *uuid, const char *codec)
|
||
|
return find_presets(uuid, id, 0x0000, 0x0000);
|
||
|
}
|
||
|
|
||
|
+static bool match_custom_name(const void *data, const void *match_data)
|
||
|
+{
|
||
|
+ const struct codec_preset *preset = data;
|
||
|
+ const char *name = match_data;
|
||
|
+
|
||
|
+ return !strcmp(preset->name, name);
|
||
|
+}
|
||
|
+
|
||
|
static struct codec_preset *preset_find_name(struct preset *preset,
|
||
|
const char *name)
|
||
|
{
|
||
|
@@ -1567,8 +1575,6 @@ static struct codec_preset *preset_find_name(struct preset *preset,
|
||
|
|
||
|
if (!name)
|
||
|
return preset->default_preset;
|
||
|
- else if (!strcmp(name, "custom"))
|
||
|
- return &preset->custom;
|
||
|
|
||
|
for (i = 0; i < preset->num_presets; i++) {
|
||
|
struct codec_preset *p;
|
||
|
@@ -1579,19 +1585,7 @@ static struct codec_preset *preset_find_name(struct preset *preset,
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
- return NULL;
|
||
|
-}
|
||
|
-
|
||
|
-static struct codec_preset *find_preset(const char *uuid, const char *codec,
|
||
|
- const char *name)
|
||
|
-{
|
||
|
- struct preset *preset;
|
||
|
-
|
||
|
- preset = find_presets_name(uuid, codec);
|
||
|
- if (!preset)
|
||
|
- return NULL;
|
||
|
-
|
||
|
- return preset_find_name(preset, name);
|
||
|
+ return queue_find(preset->custom, match_custom_name, name);
|
||
|
}
|
||
|
|
||
|
static DBusMessage *endpoint_select_config_reply(DBusMessage *msg,
|
||
|
@@ -2816,10 +2810,11 @@ static void endpoint_free(void *data)
|
||
|
if (ep->msg)
|
||
|
dbus_message_unref(ep->msg);
|
||
|
|
||
|
- if (ep->codec == 0xff) {
|
||
|
- free(ep->preset->custom.name);
|
||
|
+ queue_destroy(ep->preset->custom, free);
|
||
|
+ ep->preset->custom = NULL;
|
||
|
+
|
||
|
+ if (ep->codec == 0xff)
|
||
|
free(ep->preset);
|
||
|
- }
|
||
|
|
||
|
queue_destroy(ep->acquiring, NULL);
|
||
|
queue_destroy(ep->transports, free);
|
||
|
@@ -3365,6 +3360,36 @@ static const struct capabilities *find_capabilities(const char *uuid,
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
+static struct codec_preset *codec_preset_new(const char *name)
|
||
|
+{
|
||
|
+ struct codec_preset *codec;
|
||
|
+
|
||
|
+ codec = new0(struct codec_preset, 1);
|
||
|
+ codec->name = strdup(name);
|
||
|
+ codec->custom = true;
|
||
|
+
|
||
|
+ return codec;
|
||
|
+}
|
||
|
+
|
||
|
+static struct codec_preset *codec_preset_add(struct preset *preset,
|
||
|
+ const char *name)
|
||
|
+{
|
||
|
+ struct codec_preset *codec;
|
||
|
+
|
||
|
+ codec = preset_find_name(preset, name);
|
||
|
+ if (codec)
|
||
|
+ return codec;
|
||
|
+
|
||
|
+ codec = codec_preset_new(name);
|
||
|
+
|
||
|
+ if (!preset->custom)
|
||
|
+ preset->custom = queue_new();
|
||
|
+
|
||
|
+ queue_push_tail(preset->custom, codec);
|
||
|
+
|
||
|
+ return codec;
|
||
|
+}
|
||
|
+
|
||
|
static void cmd_register_endpoint(int argc, char *argv[])
|
||
|
{
|
||
|
struct endpoint *ep;
|
||
|
@@ -3390,8 +3415,8 @@ static void cmd_register_endpoint(int argc, char *argv[])
|
||
|
ep->codec = 0xff;
|
||
|
parse_vendor_codec(argv[2], &ep->vid, &ep->cid);
|
||
|
ep->preset = new0(struct preset, 1);
|
||
|
- ep->preset->custom.name = strdup("custom");
|
||
|
- ep->preset->default_preset = &ep->preset->custom;
|
||
|
+ ep->preset->default_preset = codec_preset_add(ep->preset,
|
||
|
+ "custom");
|
||
|
} else {
|
||
|
ep->preset = find_presets_name(ep->uuid, argv[2]);
|
||
|
}
|
||
|
@@ -4060,21 +4085,27 @@ static void custom_frequency(const char *input, void *user_data)
|
||
|
custom_duration, user_data);
|
||
|
}
|
||
|
|
||
|
+static void foreach_custom_preset_print(void *data, void *user_data)
|
||
|
+{
|
||
|
+ struct codec_preset *p = data;
|
||
|
+ struct preset *preset = user_data;
|
||
|
+
|
||
|
+ bt_shell_printf("%s%s\n", p == preset->default_preset ? "*" : "",
|
||
|
+ p->name);
|
||
|
+}
|
||
|
+
|
||
|
static void print_presets(struct preset *preset)
|
||
|
{
|
||
|
size_t i;
|
||
|
struct codec_preset *p;
|
||
|
|
||
|
- p = &preset->custom;
|
||
|
-
|
||
|
- bt_shell_printf("%s%s\n", p == preset->default_preset ? "*" : "",
|
||
|
- p->name);
|
||
|
-
|
||
|
for (i = 0; i < preset->num_presets; i++) {
|
||
|
p = &preset->presets[i];
|
||
|
bt_shell_printf("%s%s\n", p == preset->default_preset ?
|
||
|
"*" : "", p->name);
|
||
|
}
|
||
|
+
|
||
|
+ queue_foreach(preset->custom, foreach_custom_preset_print, preset);
|
||
|
}
|
||
|
|
||
|
static void cmd_presets_endpoint(int argc, char *argv[])
|
||
|
@@ -4082,29 +4113,42 @@ static void cmd_presets_endpoint(int argc, char *argv[])
|
||
|
struct preset *preset;
|
||
|
struct codec_preset *default_preset = NULL;
|
||
|
|
||
|
- if (argc > 3) {
|
||
|
- default_preset = find_preset(argv[1], argv[2], argv[3]);
|
||
|
- if (!default_preset) {
|
||
|
- bt_shell_printf("Preset %s not found\n", argv[3]);
|
||
|
- return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
preset = find_presets_name(argv[1], argv[2]);
|
||
|
if (!preset) {
|
||
|
bt_shell_printf("No preset found\n");
|
||
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
- if (default_preset) {
|
||
|
+ if (argc > 3) {
|
||
|
+ default_preset = codec_preset_add(preset, argv[3]);
|
||
|
+ if (!default_preset) {
|
||
|
+ bt_shell_printf("Preset %s not found\n", argv[3]);
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
preset->default_preset = default_preset;
|
||
|
- goto done;
|
||
|
- }
|
||
|
|
||
|
- print_presets(preset);
|
||
|
+ if (argc > 4) {
|
||
|
+ struct iovec *iov = (void *)&default_preset->data;
|
||
|
|
||
|
-done:
|
||
|
- if (default_preset && !strcmp(default_preset->name, "custom")) {
|
||
|
+ iov->iov_base = str2bytearray(argv[4], &iov->iov_len);
|
||
|
+ if (!iov->iov_base) {
|
||
|
+ bt_shell_printf("Invalid configuration %s\n",
|
||
|
+ argv[4]);
|
||
|
+ return bt_shell_noninteractive_quit(
|
||
|
+ EXIT_FAILURE);
|
||
|
+ }
|
||
|
+
|
||
|
+ bt_shell_prompt_input("QoS", "Enter Target Latency "
|
||
|
+ "(Low, Balance, High):",
|
||
|
+ custom_target_latency,
|
||
|
+ default_preset);
|
||
|
+
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ } else
|
||
|
+ print_presets(preset);
|
||
|
+
|
||
|
+ if (default_preset && default_preset->custom) {
|
||
|
bt_shell_prompt_input("Codec", "Enter frequency (Khz):",
|
||
|
custom_frequency, default_preset);
|
||
|
return;
|
||
|
@@ -4133,9 +4177,9 @@ static const struct bt_shell_menu endpoint_menu = {
|
||
|
cmd_config_endpoint,
|
||
|
"Configure Endpoint",
|
||
|
endpoint_generator },
|
||
|
- { "presets", "<UUID> <codec[:company]> [default]",
|
||
|
+ { "presets", "<UUID> <codec[:company]> [preset] [config]",
|
||
|
cmd_presets_endpoint,
|
||
|
- "List available presets",
|
||
|
+ "List or add presets",
|
||
|
uuid_generator },
|
||
|
{} },
|
||
|
};
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 957c956112cc2bba528fe8df4a0a21d221a617ca Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Thu, 18 Jul 2024 13:58:52 -0400
|
||
|
Subject: [PATCH 18/46] client/player: Fix printing errors when
|
||
|
transport->filename is not set
|
||
|
|
||
|
If transport->filename is not set don't attempt to write to the
|
||
|
transport->fd.
|
||
|
---
|
||
|
client/player.c | 4 ++--
|
||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index 26190fef7bc1..5b0b918fb8d7 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -4575,10 +4575,10 @@ static bool transport_recv(struct io *io, void *user_data)
|
||
|
|
||
|
transport->seq++;
|
||
|
|
||
|
- if (transport->fd >= 0) {
|
||
|
+ if (transport->filename) {
|
||
|
len = write(transport->fd, buf, ret);
|
||
|
if (len < 0)
|
||
|
- bt_shell_printf("Unable to write: %s (%d)",
|
||
|
+ bt_shell_printf("Unable to write: %s (%d)\n",
|
||
|
strerror(errno), -errno);
|
||
|
}
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 0bad3d5cbea84b24d53e86de7c419e893bb19a93 Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 11:11:31 +0300
|
||
|
Subject: [PATCH 19/46] bap: Fix crash in bap_bcast_remove
|
||
|
|
||
|
This adds a check for the PA request dequeued in bap_bcast_remove,
|
||
|
to avoid accessing a member within a NULL pointer.
|
||
|
---
|
||
|
profiles/audio/bap.c | 2 +-
|
||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
|
||
|
index afa938091996..16c02524f2d0 100644
|
||
|
--- a/profiles/audio/bap.c
|
||
|
+++ b/profiles/audio/bap.c
|
||
|
@@ -3194,7 +3194,7 @@ static void bap_bcast_remove(struct btd_service *service)
|
||
|
*/
|
||
|
req = queue_remove_if(data->adapter->bcast_pa_requests,
|
||
|
match_service, service);
|
||
|
- if (req->io_id) {
|
||
|
+ if (req && req->io_id) {
|
||
|
g_source_remove(req->io_id);
|
||
|
req->io_id = 0;
|
||
|
}
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From caa4202a7ee3423211733f7883641c77666dfbbf Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:21:58 +0300
|
||
|
Subject: [PATCH 20/46] shared/bap: Add separate API to merge caps
|
||
|
|
||
|
This moves the logic to merge L2 and L3 capabilities discovered
|
||
|
inside a BASE structure in a public API.
|
||
|
---
|
||
|
src/shared/bap.c | 40 ++++++++++++++++++++++++----------------
|
||
|
src/shared/bap.h | 2 ++
|
||
|
2 files changed, 26 insertions(+), 16 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index d59eac8cca16..1259ee3c90ef 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -6607,29 +6607,21 @@ static struct bt_ltv_match bap_check_bis(struct bt_bap_db *ldb,
|
||
|
return compare_data;
|
||
|
}
|
||
|
|
||
|
-void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
- struct bt_bap_codec *codec,
|
||
|
- struct iovec *l2_caps,
|
||
|
- struct iovec *l3_caps,
|
||
|
- struct bt_bap_pac **lpac,
|
||
|
- struct iovec **caps)
|
||
|
+struct iovec *bt_bap_merge_caps(struct iovec *l2_caps, struct iovec *l3_caps)
|
||
|
{
|
||
|
struct bt_ltv_extract merge_data = {0};
|
||
|
- struct bt_ltv_match match_data;
|
||
|
|
||
|
if (!l2_caps)
|
||
|
/* Codec_Specific_Configuration parameters shall
|
||
|
* be present at Level 2.
|
||
|
*/
|
||
|
- return;
|
||
|
+ return NULL;
|
||
|
|
||
|
- if (!l3_caps) {
|
||
|
+ if (!l3_caps)
|
||
|
/* Codec_Specific_Configuration parameters may
|
||
|
* be present at Level 3.
|
||
|
*/
|
||
|
- merge_data.result = util_iov_dup(l2_caps, 1);
|
||
|
- goto done;
|
||
|
- }
|
||
|
+ return util_iov_dup(l2_caps, 1);
|
||
|
|
||
|
merge_data.src = l3_caps;
|
||
|
merge_data.result = new0(struct iovec, 1);
|
||
|
@@ -6642,17 +6634,33 @@ void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
NULL,
|
||
|
bap_sink_check_level2_ltv, &merge_data);
|
||
|
|
||
|
-done:
|
||
|
+ return merge_data.result;
|
||
|
+}
|
||
|
+
|
||
|
+void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
+ struct bt_bap_codec *codec,
|
||
|
+ struct iovec *l2_caps,
|
||
|
+ struct iovec *l3_caps,
|
||
|
+ struct bt_bap_pac **lpac,
|
||
|
+ struct iovec **caps)
|
||
|
+{
|
||
|
+ struct iovec *merged_caps;
|
||
|
+ struct bt_ltv_match match_data;
|
||
|
+
|
||
|
+ merged_caps = bt_bap_merge_caps(l2_caps, l3_caps);
|
||
|
+ if (!merged_caps)
|
||
|
+ return;
|
||
|
+
|
||
|
/* Check each BIS Codec Specific Configuration LTVs against our Codec
|
||
|
* Specific Capabilities and if the BIS matches create a PAC with it
|
||
|
*/
|
||
|
- match_data = bap_check_bis(bap->ldb, merge_data.result);
|
||
|
+ match_data = bap_check_bis(bap->ldb, merged_caps);
|
||
|
if (match_data.found == true) {
|
||
|
- *caps = merge_data.result;
|
||
|
+ *caps = merged_caps;
|
||
|
*lpac = match_data.data;
|
||
|
DBG(bap, "Matching BIS %i", bis_index);
|
||
|
} else {
|
||
|
- util_iov_free(merge_data.result, 1);
|
||
|
+ util_iov_free(merged_caps, 1);
|
||
|
*caps = NULL;
|
||
|
*lpac = NULL;
|
||
|
}
|
||
|
diff --git a/src/shared/bap.h b/src/shared/bap.h
|
||
|
index b35b2711edb9..e63161dca4e8 100644
|
||
|
--- a/src/shared/bap.h
|
||
|
+++ b/src/shared/bap.h
|
||
|
@@ -251,6 +251,8 @@ bool bt_bap_pac_bcast_is_local(struct bt_bap *bap, struct bt_bap_pac *pac);
|
||
|
|
||
|
struct iovec *bt_bap_stream_get_base(struct bt_bap_stream *stream);
|
||
|
|
||
|
+struct iovec *bt_bap_merge_caps(struct iovec *l2_caps, struct iovec *l3_caps);
|
||
|
+
|
||
|
void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
struct bt_bap_codec *codec,
|
||
|
struct iovec *l2_caps,
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 679349fbc9f2eaf4216cca0ca45f25e4d2829c9d Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:21:59 +0300
|
||
|
Subject: [PATCH 21/46] shared/bap: Update bt_bap_verify_bis to receive caps
|
||
|
|
||
|
This updates bt_bap_verify_bis to receive the already merged L2 and L3
|
||
|
capabilities, instead of computing it internally.
|
||
|
---
|
||
|
profiles/audio/bap.c | 11 ++++++++---
|
||
|
src/shared/bap.c | 15 ++++-----------
|
||
|
src/shared/bap.h | 6 ++----
|
||
|
unit/test-bap.c | 7 ++++---
|
||
|
4 files changed, 18 insertions(+), 21 deletions(-)
|
||
|
|
||
|
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
|
||
|
index 16c02524f2d0..81b5051f089a 100644
|
||
|
--- a/profiles/audio/bap.c
|
||
|
+++ b/profiles/audio/bap.c
|
||
|
@@ -1191,12 +1191,17 @@ static bool parse_base(struct bap_data *bap_data, struct bt_iso_base *base,
|
||
|
l3_caps->iov_len, NULL, print_ltv,
|
||
|
func);
|
||
|
|
||
|
+ merged_caps = bt_bap_merge_caps(l2_caps, l3_caps);
|
||
|
+ if (!merged_caps) {
|
||
|
+ free(path);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
/* Check if this BIS matches any local PAC */
|
||
|
bt_bap_verify_bis(bap_data->bap, bis_index, &codec,
|
||
|
- l2_caps, l3_caps, &matched_lpac,
|
||
|
- &merged_caps);
|
||
|
+ merged_caps, &matched_lpac);
|
||
|
|
||
|
- if (matched_lpac == NULL || merged_caps == NULL) {
|
||
|
+ if (matched_lpac == NULL) {
|
||
|
free(path);
|
||
|
continue;
|
||
|
}
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index 1259ee3c90ef..3381ffdd43ee 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -6639,29 +6639,22 @@ struct iovec *bt_bap_merge_caps(struct iovec *l2_caps, struct iovec *l3_caps)
|
||
|
|
||
|
void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
struct bt_bap_codec *codec,
|
||
|
- struct iovec *l2_caps,
|
||
|
- struct iovec *l3_caps,
|
||
|
- struct bt_bap_pac **lpac,
|
||
|
- struct iovec **caps)
|
||
|
+ struct iovec *caps,
|
||
|
+ struct bt_bap_pac **lpac)
|
||
|
{
|
||
|
- struct iovec *merged_caps;
|
||
|
struct bt_ltv_match match_data;
|
||
|
|
||
|
- merged_caps = bt_bap_merge_caps(l2_caps, l3_caps);
|
||
|
- if (!merged_caps)
|
||
|
+ if (!caps)
|
||
|
return;
|
||
|
|
||
|
/* Check each BIS Codec Specific Configuration LTVs against our Codec
|
||
|
* Specific Capabilities and if the BIS matches create a PAC with it
|
||
|
*/
|
||
|
- match_data = bap_check_bis(bap->ldb, merged_caps);
|
||
|
+ match_data = bap_check_bis(bap->ldb, caps);
|
||
|
if (match_data.found == true) {
|
||
|
- *caps = merged_caps;
|
||
|
*lpac = match_data.data;
|
||
|
DBG(bap, "Matching BIS %i", bis_index);
|
||
|
} else {
|
||
|
- util_iov_free(merged_caps, 1);
|
||
|
- *caps = NULL;
|
||
|
*lpac = NULL;
|
||
|
}
|
||
|
|
||
|
diff --git a/src/shared/bap.h b/src/shared/bap.h
|
||
|
index e63161dca4e8..3e68f00e2e29 100644
|
||
|
--- a/src/shared/bap.h
|
||
|
+++ b/src/shared/bap.h
|
||
|
@@ -255,8 +255,6 @@ struct iovec *bt_bap_merge_caps(struct iovec *l2_caps, struct iovec *l3_caps);
|
||
|
|
||
|
void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
struct bt_bap_codec *codec,
|
||
|
- struct iovec *l2_caps,
|
||
|
- struct iovec *l3_caps,
|
||
|
- struct bt_bap_pac **lpac,
|
||
|
- struct iovec **caps);
|
||
|
+ struct iovec *caps,
|
||
|
+ struct bt_bap_pac **lpac);
|
||
|
|
||
|
diff --git a/unit/test-bap.c b/unit/test-bap.c
|
||
|
index 9dd7a45e89c1..4b47d6363a80 100644
|
||
|
--- a/unit/test-bap.c
|
||
|
+++ b/unit/test-bap.c
|
||
|
@@ -587,12 +587,13 @@ static void bsnk_pac_added(struct bt_bap_pac *pac, void *user_data)
|
||
|
codec.id = LC3_ID;
|
||
|
|
||
|
for (uint8_t i = 0; i < data->cfg->streams; i++) {
|
||
|
- bt_bap_verify_bis(data->bap, bis_idx++, &codec,
|
||
|
- &data->cfg->cc, NULL, &lpac, &cc);
|
||
|
+ cc = bt_bap_merge_caps(&data->cfg->cc, NULL);
|
||
|
+ g_assert(cc);
|
||
|
+
|
||
|
+ bt_bap_verify_bis(data->bap, bis_idx++, &codec, cc, &lpac);
|
||
|
|
||
|
g_assert(lpac);
|
||
|
g_assert(pac == lpac);
|
||
|
- g_assert(cc);
|
||
|
|
||
|
stream = bt_bap_stream_new(data->bap,
|
||
|
pac, NULL, &data->cfg->qos, cc);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From bbcf4891cd46f53e35761db808155dc0fb89b175 Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:22:00 +0300
|
||
|
Subject: [PATCH 22/46] shared/bap: Remove unused param from bt_bap_verify_bis
|
||
|
|
||
|
This removes the codec parameter from bt_bap_verify_bis,
|
||
|
since it is not used.
|
||
|
---
|
||
|
profiles/audio/bap.c | 2 +-
|
||
|
src/shared/bap.c | 1 -
|
||
|
src/shared/bap.h | 1 -
|
||
|
unit/test-bap.c | 8 +-------
|
||
|
4 files changed, 2 insertions(+), 10 deletions(-)
|
||
|
|
||
|
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
|
||
|
index 81b5051f089a..b76d5385fa10 100644
|
||
|
--- a/profiles/audio/bap.c
|
||
|
+++ b/profiles/audio/bap.c
|
||
|
@@ -1198,7 +1198,7 @@ static bool parse_base(struct bap_data *bap_data, struct bt_iso_base *base,
|
||
|
}
|
||
|
|
||
|
/* Check if this BIS matches any local PAC */
|
||
|
- bt_bap_verify_bis(bap_data->bap, bis_index, &codec,
|
||
|
+ bt_bap_verify_bis(bap_data->bap, bis_index,
|
||
|
merged_caps, &matched_lpac);
|
||
|
|
||
|
if (matched_lpac == NULL) {
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index 3381ffdd43ee..d2a500e486ed 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -6638,7 +6638,6 @@ struct iovec *bt_bap_merge_caps(struct iovec *l2_caps, struct iovec *l3_caps)
|
||
|
}
|
||
|
|
||
|
void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
- struct bt_bap_codec *codec,
|
||
|
struct iovec *caps,
|
||
|
struct bt_bap_pac **lpac)
|
||
|
{
|
||
|
diff --git a/src/shared/bap.h b/src/shared/bap.h
|
||
|
index 3e68f00e2e29..bf928bc2d577 100644
|
||
|
--- a/src/shared/bap.h
|
||
|
+++ b/src/shared/bap.h
|
||
|
@@ -254,7 +254,6 @@ struct iovec *bt_bap_stream_get_base(struct bt_bap_stream *stream);
|
||
|
struct iovec *bt_bap_merge_caps(struct iovec *l2_caps, struct iovec *l3_caps);
|
||
|
|
||
|
void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
- struct bt_bap_codec *codec,
|
||
|
struct iovec *caps,
|
||
|
struct bt_bap_pac **lpac);
|
||
|
|
||
|
diff --git a/unit/test-bap.c b/unit/test-bap.c
|
||
|
index 4b47d6363a80..9cfc8c403ef0 100644
|
||
|
--- a/unit/test-bap.c
|
||
|
+++ b/unit/test-bap.c
|
||
|
@@ -575,22 +575,16 @@ static void bsnk_pac_added(struct bt_bap_pac *pac, void *user_data)
|
||
|
struct test_data *data = user_data;
|
||
|
struct bt_bap_pac *lpac;
|
||
|
struct iovec *cc;
|
||
|
- struct bt_bap_codec codec = {0};
|
||
|
struct bt_bap_stream *stream;
|
||
|
uint8_t bis_idx = 1;
|
||
|
|
||
|
bt_bap_pac_set_ops(pac, &bcast_pac_ops, NULL);
|
||
|
|
||
|
- if (data->cfg->vs)
|
||
|
- codec.id = 0xff;
|
||
|
- else
|
||
|
- codec.id = LC3_ID;
|
||
|
-
|
||
|
for (uint8_t i = 0; i < data->cfg->streams; i++) {
|
||
|
cc = bt_bap_merge_caps(&data->cfg->cc, NULL);
|
||
|
g_assert(cc);
|
||
|
|
||
|
- bt_bap_verify_bis(data->bap, bis_idx++, &codec, cc, &lpac);
|
||
|
+ bt_bap_verify_bis(data->bap, bis_idx++, cc, &lpac);
|
||
|
|
||
|
g_assert(lpac);
|
||
|
g_assert(pac == lpac);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 662aee4357f8975763280fec0e6cd35b2082200d Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:22:01 +0300
|
||
|
Subject: [PATCH 23/46] shared/bap: Allow checking bis caps against peer caps
|
||
|
|
||
|
A BAP Broadcast Assistant needs to match stream capabilities with
|
||
|
capabilities discovered in the Sink PAC characteristic on the peer.
|
||
|
|
||
|
This updates bt_bap_verify_bis to check the provided stream capabilities
|
||
|
against local or remote capabilities, depending on the bap structure
|
||
|
provided:
|
||
|
|
||
|
If the device is acting as a BAP Broadcast Sink and the bap session was
|
||
|
created after scanning a Broadcast Source, the stream caps will be matched
|
||
|
with the local broadcast sink PAC.
|
||
|
|
||
|
If the device is acting as a Broadcast Assistant and the bap session is a
|
||
|
client session with a BAP Scan Delegator, the stream caps will be matched
|
||
|
with the PAC records populated in the rdb at service discovery.
|
||
|
---
|
||
|
src/shared/bap.c | 26 ++++++++++++++++++++------
|
||
|
1 file changed, 20 insertions(+), 6 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index d2a500e486ed..44fb06169e4e 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -6577,7 +6577,7 @@ static void bap_sink_match_allocation(size_t i, uint8_t l, uint8_t t,
|
||
|
data->found = false;
|
||
|
}
|
||
|
|
||
|
-static struct bt_ltv_match bap_check_bis(struct bt_bap_db *ldb,
|
||
|
+static struct bt_ltv_match bap_check_bis(uint32_t sink_loc, struct queue *pacs,
|
||
|
struct iovec *bis_data)
|
||
|
{
|
||
|
struct bt_ltv_match compare_data = {};
|
||
|
@@ -6588,10 +6588,10 @@ static struct bt_ltv_match bap_check_bis(struct bt_bap_db *ldb,
|
||
|
*/
|
||
|
compare_data.found = true;
|
||
|
|
||
|
- if (ldb->pacs->sink_loc_value) {
|
||
|
+ if (sink_loc) {
|
||
|
uint8_t type = BAP_CHANNEL_ALLOCATION_LTV_TYPE;
|
||
|
|
||
|
- compare_data.data32 = ldb->pacs->sink_loc_value;
|
||
|
+ compare_data.data32 = sink_loc;
|
||
|
util_ltv_foreach(bis_data->iov_base, bis_data->iov_len, &type,
|
||
|
bap_sink_match_allocation, &compare_data);
|
||
|
}
|
||
|
@@ -6600,8 +6600,7 @@ static struct bt_ltv_match bap_check_bis(struct bt_bap_db *ldb,
|
||
|
if (compare_data.found) {
|
||
|
compare_data.data = bis_data;
|
||
|
compare_data.found = false;
|
||
|
- queue_foreach(ldb->broadcast_sinks, check_local_pac,
|
||
|
- &compare_data);
|
||
|
+ queue_foreach(pacs, check_local_pac, &compare_data);
|
||
|
}
|
||
|
|
||
|
return compare_data;
|
||
|
@@ -6642,14 +6641,29 @@ void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index,
|
||
|
struct bt_bap_pac **lpac)
|
||
|
{
|
||
|
struct bt_ltv_match match_data;
|
||
|
+ uint32_t sink_loc;
|
||
|
+ struct queue *pacs;
|
||
|
|
||
|
if (!caps)
|
||
|
return;
|
||
|
|
||
|
+ /* If the bap session corresponds to a client connection with
|
||
|
+ * a BAP Server, bis caps should be checked against peer caps.
|
||
|
+ * If the bap session corresponds to a scanned broadcast source,
|
||
|
+ * bis caps should be checked against local broadcast sink caps.
|
||
|
+ */
|
||
|
+ if (bap->client) {
|
||
|
+ sink_loc = bap->rdb->pacs->sink_loc_value;
|
||
|
+ pacs = bap->rdb->sinks;
|
||
|
+ } else {
|
||
|
+ sink_loc = bap->ldb->pacs->sink_loc_value;
|
||
|
+ pacs = bap->ldb->broadcast_sinks;
|
||
|
+ }
|
||
|
+
|
||
|
/* Check each BIS Codec Specific Configuration LTVs against our Codec
|
||
|
* Specific Capabilities and if the BIS matches create a PAC with it
|
||
|
*/
|
||
|
- match_data = bap_check_bis(bap->ldb, caps);
|
||
|
+ match_data = bap_check_bis(sink_loc, pacs, caps);
|
||
|
if (match_data.found == true) {
|
||
|
*lpac = match_data.data;
|
||
|
DBG(bap, "Matching BIS %i", bis_index);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 2c98c478863ee9e213a4129f0f4fee2b16b678da Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:22:02 +0300
|
||
|
Subject: [PATCH 24/46] shared/bap: Append bcast sink pacs to Sink PAC char
|
||
|
|
||
|
It is mandatory for a BAP Broadcast Sink to support the PACS Server role.
|
||
|
The Sink PAC characteristic should contain PAC records that expose
|
||
|
supported audio capabilities for receiving both unicast and broadcast
|
||
|
streams.
|
||
|
|
||
|
A BAP Broadcast Assistant acting as a GATT Client needs to discover the
|
||
|
Sink PAC characteristic on the BAP Scan Delegator peer (BAP Broadcast
|
||
|
Sink), in order to discover supported capabilities for receiving streams.
|
||
|
|
||
|
This commit updates the callback for handling read requests for the Sink
|
||
|
PAC characteristic, to also append Broadcast Sink pac structures to the
|
||
|
read response.
|
||
|
---
|
||
|
src/shared/bap.c | 1 +
|
||
|
1 file changed, 1 insertion(+)
|
||
|
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index 44fb06169e4e..0aa89c2781ba 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -441,6 +441,7 @@ static void pacs_sink_read(struct gatt_db_attribute *attrib,
|
||
|
iov.iov_len = 0;
|
||
|
|
||
|
queue_foreach(bdb->sinks, pac_foreach, &iov);
|
||
|
+ queue_foreach(bdb->broadcast_sinks, pac_foreach, &iov);
|
||
|
|
||
|
gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
|
||
|
iov.iov_len);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From f163913488106929081026c56c236800aa6f8269 Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:22:03 +0300
|
||
|
Subject: [PATCH 25/46] bap: Add API to get bt_bap matching device
|
||
|
|
||
|
This adds a public BAP API to obtain a reference to the bt_bap session
|
||
|
with a peer device.
|
||
|
---
|
||
|
Makefile.plugins | 2 +-
|
||
|
profiles/audio/bap.c | 21 +++++++++++++++++++++
|
||
|
profiles/audio/bap.h | 10 ++++++++++
|
||
|
3 files changed, 32 insertions(+), 1 deletion(-)
|
||
|
create mode 100644 profiles/audio/bap.h
|
||
|
|
||
|
diff --git a/Makefile.plugins b/Makefile.plugins
|
||
|
index 44fda45367d9..9dd8134b42c5 100644
|
||
|
--- a/Makefile.plugins
|
||
|
+++ b/Makefile.plugins
|
||
|
@@ -115,7 +115,7 @@ endif
|
||
|
|
||
|
if BAP
|
||
|
builtin_modules += bap
|
||
|
-builtin_sources += profiles/audio/bap.c
|
||
|
+builtin_sources += profiles/audio/bap.h profiles/audio/bap.c
|
||
|
endif
|
||
|
|
||
|
if BASS
|
||
|
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
|
||
|
index b76d5385fa10..79e9cc52791e 100644
|
||
|
--- a/profiles/audio/bap.c
|
||
|
+++ b/profiles/audio/bap.c
|
||
|
@@ -56,6 +56,8 @@
|
||
|
#include "src/log.h"
|
||
|
#include "src/error.h"
|
||
|
|
||
|
+#include "bap.h"
|
||
|
+
|
||
|
#define ISO_SOCKET_UUID "6fbaf188-05e0-496a-9885-d6ddfdb4e03e"
|
||
|
#define PACS_UUID_STR "00001850-0000-1000-8000-00805f9b34fb"
|
||
|
#define BCAAS_UUID_STR "00001852-0000-1000-8000-00805f9b34fb"
|
||
|
@@ -2751,6 +2753,25 @@ static void pac_removed_broadcast(struct bt_bap_pac *pac, void *user_data)
|
||
|
ep_unregister(ep);
|
||
|
}
|
||
|
|
||
|
+static bool match_device(const void *data, const void *match_data)
|
||
|
+{
|
||
|
+ const struct bap_data *bdata = data;
|
||
|
+ const struct btd_device *device = match_data;
|
||
|
+
|
||
|
+ return bdata->device == device;
|
||
|
+}
|
||
|
+
|
||
|
+struct bt_bap *bap_get_session(struct btd_device *device)
|
||
|
+{
|
||
|
+ struct bap_data *data;
|
||
|
+
|
||
|
+ data = queue_find(sessions, match_device, device);
|
||
|
+ if (!data)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ return data->bap;
|
||
|
+}
|
||
|
+
|
||
|
static struct bap_data *bap_data_new(struct btd_device *device)
|
||
|
{
|
||
|
struct bap_data *data;
|
||
|
diff --git a/profiles/audio/bap.h b/profiles/audio/bap.h
|
||
|
new file mode 100644
|
||
|
index 000000000000..66f8db88713a
|
||
|
--- /dev/null
|
||
|
+++ b/profiles/audio/bap.h
|
||
|
@@ -0,0 +1,10 @@
|
||
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||
|
+/*
|
||
|
+ *
|
||
|
+ * BlueZ - Bluetooth protocol stack for Linux
|
||
|
+ *
|
||
|
+ * Copyright 2024 NXP
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+struct bt_bap *bap_get_session(struct btd_device *device);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 88bf423eb525655e15890bdca84d9acb5afab122 Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:22:04 +0300
|
||
|
Subject: [PATCH 26/46] shared/bass: Add API to get GATT client reference
|
||
|
|
||
|
Some use cases require the BASS plugin to differentiate between client and
|
||
|
server BASS sessions - for example, the BAP Broadcast Assistant role only
|
||
|
considers client BASS sessions.
|
||
|
|
||
|
This adds a BASS API to obtain a reference to the bt_gatt_client structure
|
||
|
attached to the bt_bass session.
|
||
|
---
|
||
|
src/shared/bass.c | 8 ++++++++
|
||
|
src/shared/bass.h | 1 +
|
||
|
2 files changed, 9 insertions(+)
|
||
|
|
||
|
diff --git a/src/shared/bass.c b/src/shared/bass.c
|
||
|
index d82c043ac0db..268e3bd8613e 100644
|
||
|
--- a/src/shared/bass.c
|
||
|
+++ b/src/shared/bass.c
|
||
|
@@ -1683,6 +1683,14 @@ struct bt_att *bt_bass_get_att(struct bt_bass *bass)
|
||
|
return bt_gatt_client_get_att(bass->client);
|
||
|
}
|
||
|
|
||
|
+struct bt_gatt_client *bt_bass_get_client(struct bt_bass *bass)
|
||
|
+{
|
||
|
+ if (!bass)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ return bass->client;
|
||
|
+}
|
||
|
+
|
||
|
bool bt_bass_set_debug(struct bt_bass *bass, bt_bass_debug_func_t func,
|
||
|
void *user_data, bt_bass_destroy_func_t destroy)
|
||
|
{
|
||
|
diff --git a/src/shared/bass.h b/src/shared/bass.h
|
||
|
index c4b5b76baa53..1674146bca10 100644
|
||
|
--- a/src/shared/bass.h
|
||
|
+++ b/src/shared/bass.h
|
||
|
@@ -121,6 +121,7 @@ typedef void (*bt_bass_destroy_func_t)(void *user_data);
|
||
|
typedef void (*bt_bass_debug_func_t)(const char *str, void *user_data);
|
||
|
|
||
|
struct bt_att *bt_bass_get_att(struct bt_bass *bass);
|
||
|
+struct bt_gatt_client *bt_bass_get_client(struct bt_bass *bass);
|
||
|
unsigned int bt_bass_register(bt_bass_func_t attached, bt_bass_func_t detached,
|
||
|
void *user_data);
|
||
|
bool bt_bass_unregister(unsigned int id);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 77e4c0976c0d342e45f0ad1b485efd7e60863e30 Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:22:05 +0300
|
||
|
Subject: [PATCH 27/46] bass: Register MediaAssistant objects
|
||
|
|
||
|
This adds an initial implementation of the BAP Broadcast Assistant role
|
||
|
in the BASS plugin, by introducing the MediaAssistant DBus object.
|
||
|
|
||
|
The BAP plugin implements the callback to probe Broadcast Sources and
|
||
|
parse the BASE. This commit adds 2 BASS APIs, that will be called by the
|
||
|
BAP plugin to notify BISes discovered in the BASE of a broadcaster to
|
||
|
BASS, or to inform the BASS plugin that a broadcaster has been removed.
|
||
|
|
||
|
For each BASS client session, the BASS plugin checks BIS caps against
|
||
|
the peer caps, and registers a MediaAssistant object for each match.
|
||
|
---
|
||
|
Makefile.plugins | 2 +-
|
||
|
profiles/audio/bass.c | 257 ++++++++++++++++++++++++++++++++++++++++++
|
||
|
profiles/audio/bass.h | 13 +++
|
||
|
3 files changed, 271 insertions(+), 1 deletion(-)
|
||
|
create mode 100644 profiles/audio/bass.h
|
||
|
|
||
|
diff --git a/Makefile.plugins b/Makefile.plugins
|
||
|
index 9dd8134b42c5..9da29a3ce43a 100644
|
||
|
--- a/Makefile.plugins
|
||
|
+++ b/Makefile.plugins
|
||
|
@@ -120,7 +120,7 @@ endif
|
||
|
|
||
|
if BASS
|
||
|
builtin_modules += bass
|
||
|
-builtin_sources += profiles/audio/bass.c
|
||
|
+builtin_sources += profiles/audio/bass.h profiles/audio/bass.c
|
||
|
endif
|
||
|
|
||
|
if MCP
|
||
|
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
|
||
|
index 7952105c51bb..083988358735 100644
|
||
|
--- a/profiles/audio/bass.c
|
||
|
+++ b/profiles/audio/bass.c
|
||
|
@@ -39,6 +39,7 @@
|
||
|
#include "src/shared/gatt-server.h"
|
||
|
#include "src/adapter.h"
|
||
|
#include "src/shared/bass.h"
|
||
|
+#include "src/shared/bap.h"
|
||
|
|
||
|
#include "src/plugin.h"
|
||
|
#include "src/gatt-database.h"
|
||
|
@@ -48,21 +49,265 @@
|
||
|
#include "src/log.h"
|
||
|
#include "src/error.h"
|
||
|
|
||
|
+#include "bass.h"
|
||
|
+#include "bap.h"
|
||
|
+
|
||
|
#define BASS_UUID_STR "0000184f-0000-1000-8000-00805f9b34fb"
|
||
|
|
||
|
+#define MEDIA_ASSISTANT_INTERFACE "org.bluez.MediaAssistant1"
|
||
|
+
|
||
|
+enum assistant_state {
|
||
|
+ ASSISTANT_STATE_IDLE, /* Assistant object was created for
|
||
|
+ * the stream
|
||
|
+ */
|
||
|
+ ASSISTANT_STATE_PENDING, /* Assistant object was pushed */
|
||
|
+ ASSISTANT_STATE_REQUESTING, /* Remote device requires
|
||
|
+ * Broadcast_Code
|
||
|
+ */
|
||
|
+ ASSISTANT_STATE_ACTIVE, /* Remote device started receiving
|
||
|
+ * stream
|
||
|
+ */
|
||
|
+};
|
||
|
+
|
||
|
struct bass_data {
|
||
|
struct btd_device *device;
|
||
|
struct btd_service *service;
|
||
|
struct bt_bass *bass;
|
||
|
};
|
||
|
|
||
|
+struct bass_assistant {
|
||
|
+ struct btd_device *device; /* Broadcast source device */
|
||
|
+ struct bass_data *data; /* BASS session with peer device */
|
||
|
+ uint8_t sgrp;
|
||
|
+ uint8_t bis;
|
||
|
+ struct bt_iso_qos qos;
|
||
|
+ struct iovec *meta;
|
||
|
+ struct iovec *caps;
|
||
|
+ enum assistant_state state;
|
||
|
+ char *path;
|
||
|
+};
|
||
|
+
|
||
|
static struct queue *sessions;
|
||
|
+static struct queue *assistants;
|
||
|
|
||
|
static void bass_debug(const char *str, void *user_data)
|
||
|
{
|
||
|
DBG_IDX(0xffff, "%s", str);
|
||
|
}
|
||
|
|
||
|
+static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
|
||
|
+ void *user_data)
|
||
|
+{
|
||
|
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
|
||
|
+}
|
||
|
+
|
||
|
+static const GDBusMethodTable assistant_methods[] = {
|
||
|
+ {GDBUS_EXPERIMENTAL_ASYNC_METHOD("Push",
|
||
|
+ GDBUS_ARGS({ "Props", "a{sv}" }),
|
||
|
+ NULL, push)},
|
||
|
+ {},
|
||
|
+};
|
||
|
+
|
||
|
+static const char *state2str(enum assistant_state state)
|
||
|
+{
|
||
|
+ switch (state) {
|
||
|
+ case ASSISTANT_STATE_IDLE:
|
||
|
+ return "idle";
|
||
|
+ case ASSISTANT_STATE_PENDING:
|
||
|
+ return "pending";
|
||
|
+ case ASSISTANT_STATE_REQUESTING:
|
||
|
+ return "requesting";
|
||
|
+ case ASSISTANT_STATE_ACTIVE:
|
||
|
+ return "active";
|
||
|
+ }
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean get_state(const GDBusPropertyTable *property,
|
||
|
+ DBusMessageIter *iter, void *data)
|
||
|
+{
|
||
|
+ struct bass_assistant *assistant = data;
|
||
|
+ const char *state = state2str(assistant->state);
|
||
|
+
|
||
|
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &state);
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean get_metadata(const GDBusPropertyTable *property,
|
||
|
+ DBusMessageIter *iter, void *data)
|
||
|
+{
|
||
|
+ struct bass_assistant *assistant = data;
|
||
|
+ DBusMessageIter array;
|
||
|
+
|
||
|
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
|
||
|
+ DBUS_TYPE_BYTE_AS_STRING, &array);
|
||
|
+
|
||
|
+ if (assistant->meta)
|
||
|
+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
|
||
|
+ &assistant->meta->iov_base,
|
||
|
+ assistant->meta->iov_len);
|
||
|
+
|
||
|
+ dbus_message_iter_close_container(iter, &array);
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean get_qos(const GDBusPropertyTable *property,
|
||
|
+ DBusMessageIter *iter, void *data)
|
||
|
+{
|
||
|
+ struct bass_assistant *assistant = data;
|
||
|
+ DBusMessageIter dict;
|
||
|
+ uint8_t *bcode = assistant->qos.bcast.bcode;
|
||
|
+
|
||
|
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
|
||
|
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
||
|
+ DBUS_TYPE_STRING_AS_STRING
|
||
|
+ DBUS_TYPE_VARIANT_AS_STRING
|
||
|
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
|
||
|
+ &dict);
|
||
|
+
|
||
|
+ dict_append_entry(&dict, "Encryption", DBUS_TYPE_BYTE,
|
||
|
+ &assistant->qos.bcast.encryption);
|
||
|
+ dict_append_array(&dict, "BCode", DBUS_TYPE_BYTE,
|
||
|
+ &bcode, BT_BASS_BCAST_CODE_SIZE);
|
||
|
+
|
||
|
+ dbus_message_iter_close_container(iter, &dict);
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+static const GDBusPropertyTable assistant_properties[] = {
|
||
|
+ { "State", "s", get_state },
|
||
|
+ { "Metadata", "ay", get_metadata, NULL, NULL,
|
||
|
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
|
||
|
+ { "QoS", "a{sv}", get_qos, NULL, NULL,
|
||
|
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
|
||
|
+ { }
|
||
|
+};
|
||
|
+
|
||
|
+static void assistant_free(void *data)
|
||
|
+{
|
||
|
+ struct bass_assistant *assistant = data;
|
||
|
+
|
||
|
+ g_free(assistant->path);
|
||
|
+ util_iov_free(assistant->meta, 1);
|
||
|
+ util_iov_free(assistant->caps, 1);
|
||
|
+
|
||
|
+ free(assistant);
|
||
|
+}
|
||
|
+
|
||
|
+static struct bass_assistant *assistant_new(struct btd_adapter *adapter,
|
||
|
+ struct btd_device *device, struct bass_data *data,
|
||
|
+ uint8_t sgrp, uint8_t bis, struct bt_iso_qos *qos,
|
||
|
+ struct iovec *meta, struct iovec *caps)
|
||
|
+{
|
||
|
+ struct bass_assistant *assistant;
|
||
|
+ char src_addr[18];
|
||
|
+ char dev_addr[18];
|
||
|
+
|
||
|
+ assistant = new0(struct bass_assistant, 1);
|
||
|
+ if (!assistant)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ DBG("assistant %p", assistant);
|
||
|
+
|
||
|
+ assistant->device = device;
|
||
|
+ assistant->data = data;
|
||
|
+ assistant->sgrp = sgrp;
|
||
|
+ assistant->bis = bis;
|
||
|
+ assistant->qos = *qos;
|
||
|
+ assistant->meta = util_iov_dup(meta, 1);
|
||
|
+ assistant->caps = util_iov_dup(caps, 1);
|
||
|
+
|
||
|
+ ba2str(device_get_address(device), src_addr);
|
||
|
+ ba2str(device_get_address(data->device), dev_addr);
|
||
|
+
|
||
|
+ assistant->path = g_strdup_printf("%s/src_%s/dev_%s/bis%d",
|
||
|
+ adapter_get_path(adapter), src_addr, dev_addr, bis);
|
||
|
+
|
||
|
+ g_strdelimit(assistant->path, ":", '_');
|
||
|
+
|
||
|
+ if (!assistants)
|
||
|
+ assistants = queue_new();
|
||
|
+
|
||
|
+ queue_push_tail(assistants, assistant);
|
||
|
+
|
||
|
+ return assistant;
|
||
|
+}
|
||
|
+
|
||
|
+void bass_add_stream(struct btd_device *device, struct iovec *meta,
|
||
|
+ struct iovec *caps, struct bt_iso_qos *qos,
|
||
|
+ uint8_t sgrp, uint8_t bis)
|
||
|
+{
|
||
|
+ const struct queue_entry *entry;
|
||
|
+ struct bt_bap *bap;
|
||
|
+ struct bt_bap_pac *pac;
|
||
|
+ struct bass_assistant *assistant;
|
||
|
+ char addr[18];
|
||
|
+
|
||
|
+ for (entry = queue_get_entries(sessions); entry; entry = entry->next) {
|
||
|
+ struct bass_data *data = entry->data;
|
||
|
+ struct btd_adapter *adapter = device_get_adapter(data->device);
|
||
|
+
|
||
|
+ if (!bt_bass_get_client(data->bass))
|
||
|
+ /* Only client sessions must be handled */
|
||
|
+ continue;
|
||
|
+
|
||
|
+ bap = bap_get_session(data->device);
|
||
|
+ if (!bap)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ /* Check stream capabilities against peer caps. */
|
||
|
+ bt_bap_verify_bis(bap, bis, caps, &pac);
|
||
|
+
|
||
|
+ if (!pac)
|
||
|
+ /* Capabilities did not match. */
|
||
|
+ continue;
|
||
|
+
|
||
|
+ ba2str(device_get_address(device), addr);
|
||
|
+
|
||
|
+ DBG("%s data %p BIS %d", addr, data, bis);
|
||
|
+
|
||
|
+ assistant = assistant_new(adapter, device, data, sgrp,
|
||
|
+ bis, qos, meta, caps);
|
||
|
+
|
||
|
+ if (g_dbus_register_interface(btd_get_dbus_connection(),
|
||
|
+ assistant->path,
|
||
|
+ MEDIA_ASSISTANT_INTERFACE,
|
||
|
+ assistant_methods, NULL,
|
||
|
+ assistant_properties,
|
||
|
+ assistant,
|
||
|
+ assistant_free) == FALSE)
|
||
|
+ DBG("Could not register path %s", assistant->path);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static bool assistant_match_device(const void *data, const void *match_data)
|
||
|
+{
|
||
|
+ const struct bass_assistant *assistant = data;
|
||
|
+ const struct btd_device *device = match_data;
|
||
|
+
|
||
|
+ return (assistant->device == device);
|
||
|
+}
|
||
|
+
|
||
|
+static void unregister_assistant(void *data)
|
||
|
+{
|
||
|
+ struct bass_assistant *assistant = data;
|
||
|
+
|
||
|
+ DBG("%p", assistant);
|
||
|
+
|
||
|
+ g_dbus_unregister_interface(btd_get_dbus_connection(),
|
||
|
+ assistant->path, MEDIA_ASSISTANT_INTERFACE);
|
||
|
+}
|
||
|
+
|
||
|
+void bass_remove_stream(struct btd_device *device)
|
||
|
+{
|
||
|
+ queue_remove_all(assistants, assistant_match_device,
|
||
|
+ device, unregister_assistant);
|
||
|
+}
|
||
|
+
|
||
|
static struct bass_data *bass_data_new(struct btd_device *device)
|
||
|
{
|
||
|
struct bass_data *data;
|
||
|
@@ -101,6 +346,14 @@ static bool match_data(const void *data, const void *match_data)
|
||
|
return bdata->bass == bass;
|
||
|
}
|
||
|
|
||
|
+static bool assistant_match_data(const void *data, const void *match_data)
|
||
|
+{
|
||
|
+ const struct bass_assistant *assistant = data;
|
||
|
+ const struct bass_data *bdata = match_data;
|
||
|
+
|
||
|
+ return (assistant->data == bdata);
|
||
|
+}
|
||
|
+
|
||
|
static void bass_data_free(struct bass_data *data)
|
||
|
{
|
||
|
if (data->service) {
|
||
|
@@ -109,6 +362,10 @@ static void bass_data_free(struct bass_data *data)
|
||
|
}
|
||
|
|
||
|
bt_bass_unref(data->bass);
|
||
|
+
|
||
|
+ queue_remove_all(assistants, assistant_match_data,
|
||
|
+ data, unregister_assistant);
|
||
|
+
|
||
|
free(data);
|
||
|
}
|
||
|
|
||
|
diff --git a/profiles/audio/bass.h b/profiles/audio/bass.h
|
||
|
new file mode 100644
|
||
|
index 000000000000..5bef92946c46
|
||
|
--- /dev/null
|
||
|
+++ b/profiles/audio/bass.h
|
||
|
@@ -0,0 +1,13 @@
|
||
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||
|
+/*
|
||
|
+ *
|
||
|
+ * BlueZ - Bluetooth protocol stack for Linux
|
||
|
+ *
|
||
|
+ * Copyright 2024 NXP
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+void bass_add_stream(struct btd_device *device, struct iovec *meta,
|
||
|
+ struct iovec *caps, struct bt_iso_qos *qos,
|
||
|
+ uint8_t sgrp, uint8_t bis);
|
||
|
+void bass_remove_stream(struct btd_device *device);
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 22779f0bce61cfd5cd72f4e2c199aaa385067248 Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:22:06 +0300
|
||
|
Subject: [PATCH 28/46] bap: Notify scanned BISes to BASS
|
||
|
|
||
|
This updates the BAP implementation to also notify the BASS plugin about
|
||
|
scanned broadcast streams, or when a scanned broadcaster is removed. This
|
||
|
is needed for the BAP Broadcast Assistant role - the BASS plugin registers
|
||
|
MediaAssistant objects for each detected stream that matches the audio
|
||
|
capabilities of peer Scan Delegator devices.
|
||
|
---
|
||
|
profiles/audio/bap.c | 6 ++++++
|
||
|
1 file changed, 6 insertions(+)
|
||
|
|
||
|
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
|
||
|
index 79e9cc52791e..53f430d66171 100644
|
||
|
--- a/profiles/audio/bap.c
|
||
|
+++ b/profiles/audio/bap.c
|
||
|
@@ -57,6 +57,7 @@
|
||
|
#include "src/error.h"
|
||
|
|
||
|
#include "bap.h"
|
||
|
+#include "bass.h"
|
||
|
|
||
|
#define ISO_SOCKET_UUID "6fbaf188-05e0-496a-9885-d6ddfdb4e03e"
|
||
|
#define PACS_UUID_STR "00001850-0000-1000-8000-00805f9b34fb"
|
||
|
@@ -1199,6 +1200,9 @@ static bool parse_base(struct bap_data *bap_data, struct bt_iso_base *base,
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
+ bass_add_stream(bap_data->device, meta, merged_caps,
|
||
|
+ qos, idx, bis_index);
|
||
|
+
|
||
|
/* Check if this BIS matches any local PAC */
|
||
|
bt_bap_verify_bis(bap_data->bap, bis_index,
|
||
|
merged_caps, &matched_lpac);
|
||
|
@@ -3227,6 +3231,8 @@ static void bap_bcast_remove(struct btd_service *service)
|
||
|
free(req);
|
||
|
|
||
|
bap_data_remove(data);
|
||
|
+
|
||
|
+ bass_remove_stream(device);
|
||
|
}
|
||
|
|
||
|
static int bap_probe(struct btd_service *service)
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From a3f9970f7a8b62b426e7a00303ddb66acb79aadd Mon Sep 17 00:00:00 2001
|
||
|
From: Iulia Tanasescu <iulia.tanasescu@nxp.com>
|
||
|
Date: Tue, 16 Jul 2024 17:22:07 +0300
|
||
|
Subject: [PATCH 29/46] client: Add assistant submenu
|
||
|
|
||
|
This adds the initial implementation for the assistant menu in
|
||
|
bluetoothctl, to detect and print MediaAssistant objects.
|
||
|
|
||
|
The current BAP Broadcast Assistant implementation can be tested
|
||
|
by running bluetoothctl, connecting to a BASS Server, scanning
|
||
|
a Broadcast Source that is streaming a number of BISes with
|
||
|
audio capabilities matching the capabilities of the peer device,
|
||
|
and noticing the MediaAssistant objects being created:
|
||
|
|
||
|
client/bluetoothctl
|
||
|
[bluetooth]# [CHG] Controller 00:60:37:31:7E:3F Pairable: yes
|
||
|
[bluetooth]# AdvertisementMonitor path registered
|
||
|
[bluetooth]# scan on
|
||
|
[bluetooth]# [NEW] Device 00:60:37:94:A6:A3 00-60-37-94-A6-A3
|
||
|
[bluetooth]# connect 00:60:37:94:A6:A3
|
||
|
Attempting to connect to 00:60:37:94:A6:A3
|
||
|
[CHG] Device 00:60:37:94:A6:A3 Connected: yes
|
||
|
[00-60-37-94-A6-A3]# Connection successful
|
||
|
[00-60-37-94-A6-A3]# [NEW] Device 15:65:78:B6:52:F6 15-65-78-B6-52-F6
|
||
|
[00-60-37-94-A6-A3]# [NEW] Assistant
|
||
|
/org/bluez/hci0/src_15_65_78_B6_52_F6/dev_00_60_37_94_A6_A3/bis1
|
||
|
[00-60-37-94-A6-A3]# [NEW] Assistant
|
||
|
/org/bluez/hci0/src_15_65_78_B6_52_F6/dev_00_60_37_94_A6_A3/bis2
|
||
|
[00-60-37-94-A6-A3]# scan off
|
||
|
[00-60-37-94-A6-A3]# Diovery stopped
|
||
|
[00-60-37-94-A6-A3]# disconnect
|
||
|
Attempting to disconnect from 00:60:37:94:A6:A3
|
||
|
[00-60-37-94-A6-A3]# Successful disconnected
|
||
|
[CHG] Device 00:60:37:94:A6:A3 Connected: no
|
||
|
[bluetooth]# [DEL] Assistant
|
||
|
/org/bluez/hci0/src_15_65_78_B6_52_F6/dev_00_60_37_94_A6_A3/bis1
|
||
|
[bluetooth]# [DEL] Assistant
|
||
|
/org/bluez/hci0/src_15_65_78_B6_52_F6/dev_00_60_37_94_A6_A3/bis2
|
||
|
---
|
||
|
Makefile.tools | 3 +-
|
||
|
client/assistant.c | 164 +++++++++++++++++++++++++++++++++++++++++++++
|
||
|
client/assistant.h | 13 ++++
|
||
|
client/main.c | 5 +-
|
||
|
4 files changed, 183 insertions(+), 2 deletions(-)
|
||
|
create mode 100644 client/assistant.c
|
||
|
create mode 100644 client/assistant.h
|
||
|
|
||
|
diff --git a/Makefile.tools b/Makefile.tools
|
||
|
index 679c914bf8cd..f4f9e82dc7c4 100644
|
||
|
--- a/Makefile.tools
|
||
|
+++ b/Makefile.tools
|
||
|
@@ -13,7 +13,8 @@ client_bluetoothctl_SOURCES = client/main.c \
|
||
|
client/gatt.h client/gatt.c \
|
||
|
client/admin.h client/admin.c \
|
||
|
client/player.h client/player.c \
|
||
|
- client/mgmt.h client/mgmt.c
|
||
|
+ client/mgmt.h client/mgmt.c \
|
||
|
+ client/assistant.h client/assistant.c
|
||
|
client_bluetoothctl_LDADD = lib/libbluetooth-internal.la \
|
||
|
gdbus/libgdbus-internal.la src/libshared-glib.la \
|
||
|
$(GLIB_LIBS) $(DBUS_LIBS) -lreadline
|
||
|
diff --git a/client/assistant.c b/client/assistant.c
|
||
|
new file mode 100644
|
||
|
index 000000000000..69a955c18655
|
||
|
--- /dev/null
|
||
|
+++ b/client/assistant.c
|
||
|
@@ -0,0 +1,164 @@
|
||
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
+/*
|
||
|
+ *
|
||
|
+ * BlueZ - Bluetooth protocol stack for Linux
|
||
|
+ *
|
||
|
+ * Copyright 2024 NXP
|
||
|
+ *
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#ifdef HAVE_CONFIG_H
|
||
|
+#include <config.h>
|
||
|
+#endif
|
||
|
+
|
||
|
+#define _GNU_SOURCE
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdbool.h>
|
||
|
+#include <inttypes.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+#include <glib.h>
|
||
|
+
|
||
|
+#include "gdbus/gdbus.h"
|
||
|
+
|
||
|
+#include "lib/bluetooth.h"
|
||
|
+#include "lib/uuid.h"
|
||
|
+
|
||
|
+#include "src/shared/util.h"
|
||
|
+#include "src/shared/shell.h"
|
||
|
+#include "src/shared/io.h"
|
||
|
+#include "src/shared/queue.h"
|
||
|
+#include "print.h"
|
||
|
+#include "assistant.h"
|
||
|
+
|
||
|
+/* String display constants */
|
||
|
+#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
|
||
|
+#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
|
||
|
+#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
|
||
|
+
|
||
|
+#define MEDIA_ASSISTANT_INTERFACE "org.bluez.MediaAssistant1"
|
||
|
+
|
||
|
+static DBusConnection *dbus_conn;
|
||
|
+
|
||
|
+static GList *assistants;
|
||
|
+
|
||
|
+static char *proxy_description(GDBusProxy *proxy, const char *title,
|
||
|
+ const char *description)
|
||
|
+{
|
||
|
+ const char *path;
|
||
|
+
|
||
|
+ path = g_dbus_proxy_get_path(proxy);
|
||
|
+
|
||
|
+ return g_strdup_printf("%s%s%s%s %s ",
|
||
|
+ description ? "[" : "",
|
||
|
+ description ? : "",
|
||
|
+ description ? "] " : "",
|
||
|
+ title, path);
|
||
|
+}
|
||
|
+
|
||
|
+static void print_assistant(GDBusProxy *proxy, const char *description)
|
||
|
+{
|
||
|
+ char *str;
|
||
|
+
|
||
|
+ str = proxy_description(proxy, "Assistant", description);
|
||
|
+
|
||
|
+ bt_shell_printf("%s\n", str);
|
||
|
+
|
||
|
+ g_free(str);
|
||
|
+}
|
||
|
+
|
||
|
+static void assistant_added(GDBusProxy *proxy)
|
||
|
+{
|
||
|
+ assistants = g_list_append(assistants, proxy);
|
||
|
+
|
||
|
+ print_assistant(proxy, COLORED_NEW);
|
||
|
+}
|
||
|
+
|
||
|
+static void proxy_added(GDBusProxy *proxy, void *user_data)
|
||
|
+{
|
||
|
+ const char *interface;
|
||
|
+
|
||
|
+ interface = g_dbus_proxy_get_interface(proxy);
|
||
|
+
|
||
|
+ if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE))
|
||
|
+ assistant_added(proxy);
|
||
|
+}
|
||
|
+
|
||
|
+static void assistant_removed(GDBusProxy *proxy)
|
||
|
+{
|
||
|
+ assistants = g_list_remove(assistants, proxy);
|
||
|
+
|
||
|
+ print_assistant(proxy, COLORED_DEL);
|
||
|
+}
|
||
|
+
|
||
|
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
|
||
|
+{
|
||
|
+ const char *interface;
|
||
|
+
|
||
|
+ interface = g_dbus_proxy_get_interface(proxy);
|
||
|
+
|
||
|
+ if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE))
|
||
|
+ assistant_removed(proxy);
|
||
|
+}
|
||
|
+
|
||
|
+static void assistant_property_changed(GDBusProxy *proxy, const char *name,
|
||
|
+ DBusMessageIter *iter)
|
||
|
+{
|
||
|
+ char *str;
|
||
|
+
|
||
|
+ str = proxy_description(proxy, "Assistant", COLORED_CHG);
|
||
|
+ print_iter(str, name, iter);
|
||
|
+ g_free(str);
|
||
|
+}
|
||
|
+
|
||
|
+static void property_changed(GDBusProxy *proxy, const char *name,
|
||
|
+ DBusMessageIter *iter, void *user_data)
|
||
|
+{
|
||
|
+ const char *interface;
|
||
|
+
|
||
|
+ interface = g_dbus_proxy_get_interface(proxy);
|
||
|
+
|
||
|
+ if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE))
|
||
|
+ assistant_property_changed(proxy, name, iter);
|
||
|
+}
|
||
|
+
|
||
|
+static void assistant_unregister(void *data)
|
||
|
+{
|
||
|
+ GDBusProxy *proxy = data;
|
||
|
+
|
||
|
+ bt_shell_printf("Assistant %s unregistered\n",
|
||
|
+ g_dbus_proxy_get_path(proxy));
|
||
|
+}
|
||
|
+
|
||
|
+static void disconnect_handler(DBusConnection *connection, void *user_data)
|
||
|
+{
|
||
|
+ g_list_free_full(assistants, assistant_unregister);
|
||
|
+ assistants = NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static GDBusClient * client;
|
||
|
+
|
||
|
+void assistant_add_submenu(void)
|
||
|
+{
|
||
|
+ dbus_conn = bt_shell_get_env("DBUS_CONNECTION");
|
||
|
+ if (!dbus_conn || client)
|
||
|
+ return;
|
||
|
+
|
||
|
+ client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
|
||
|
+
|
||
|
+ g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
|
||
|
+ property_changed, NULL);
|
||
|
+ g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
|
||
|
+}
|
||
|
+
|
||
|
+void assistant_remove_submenu(void)
|
||
|
+{
|
||
|
+ g_dbus_client_unref(client);
|
||
|
+ client = NULL;
|
||
|
+}
|
||
|
+
|
||
|
diff --git a/client/assistant.h b/client/assistant.h
|
||
|
new file mode 100644
|
||
|
index 000000000000..418b0b84031f
|
||
|
--- /dev/null
|
||
|
+++ b/client/assistant.h
|
||
|
@@ -0,0 +1,13 @@
|
||
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
+/*
|
||
|
+ *
|
||
|
+ * BlueZ - Bluetooth protocol stack for Linux
|
||
|
+ *
|
||
|
+ * Copyright 2024 NXP
|
||
|
+ *
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+void assistant_add_submenu(void);
|
||
|
+void assistant_remove_submenu(void);
|
||
|
+
|
||
|
diff --git a/client/main.c b/client/main.c
|
||
|
index f012ddd436ad..a96a4263849d 100644
|
||
|
--- a/client/main.c
|
||
|
+++ b/client/main.c
|
||
|
@@ -4,7 +4,7 @@
|
||
|
* BlueZ - Bluetooth protocol stack for Linux
|
||
|
*
|
||
|
* Copyright (C) 2012 Intel Corporation. All rights reserved.
|
||
|
- *
|
||
|
+ * Copyright 2024 NXP
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
@@ -34,6 +34,7 @@
|
||
|
#include "admin.h"
|
||
|
#include "player.h"
|
||
|
#include "mgmt.h"
|
||
|
+#include "assistant.h"
|
||
|
|
||
|
/* String display constants */
|
||
|
#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
|
||
|
@@ -3205,6 +3206,7 @@ int main(int argc, char *argv[])
|
||
|
admin_add_submenu();
|
||
|
player_add_submenu();
|
||
|
mgmt_add_submenu();
|
||
|
+ assistant_add_submenu();
|
||
|
|
||
|
client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
|
||
|
|
||
|
@@ -3222,6 +3224,7 @@ int main(int argc, char *argv[])
|
||
|
admin_remove_submenu();
|
||
|
player_remove_submenu();
|
||
|
mgmt_remove_submenu();
|
||
|
+ assistant_remove_submenu();
|
||
|
|
||
|
g_dbus_client_unref(client);
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 4c9d4ed059b539c696e1ebcc92b0cb2522e48a2d Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Mon, 22 Jul 2024 11:58:39 -0400
|
||
|
Subject: [PATCH 30/46] client/player: Set number of channels based on
|
||
|
locations
|
||
|
|
||
|
This sets the number of channels based on the locations set rather than
|
||
|
always hardcoding it to 3 which in certain case is incorrect and can
|
||
|
lead for the same location to be configured multiple times.
|
||
|
---
|
||
|
client/player.c | 19 ++++++++++++-------
|
||
|
1 file changed, 12 insertions(+), 7 deletions(-)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index 5b0b918fb8d7..9334a053d34d 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -1140,10 +1140,9 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn,
|
||
|
.meta = _meta, \
|
||
|
}
|
||
|
|
||
|
-#define LC3_DATA(_freq, _duration, _chan_count, _len_min, _len_max) \
|
||
|
+#define LC3_DATA(_freq, _duration, _len_min, _len_max) \
|
||
|
UTIL_IOV_INIT(0x03, LC3_FREQ, _freq, _freq >> 8, \
|
||
|
0x02, LC3_DURATION, _duration, \
|
||
|
- 0x02, LC3_CHAN_COUNT, _chan_count, \
|
||
|
0x05, LC3_FRAME_LEN, _len_min, _len_min >> 8, \
|
||
|
_len_max, _len_max >> 8)
|
||
|
|
||
|
@@ -1182,11 +1181,10 @@ static const struct capabilities {
|
||
|
*
|
||
|
* Frequencies: 8Khz 11Khz 16Khz 22Khz 24Khz 32Khz 44.1Khz 48Khz
|
||
|
* Duration: 7.5 ms 10 ms
|
||
|
- * Channel count: 3
|
||
|
* Frame length: 26-240
|
||
|
*/
|
||
|
CODEC_CAPABILITIES("pac_snk/lc3", PAC_SINK_UUID, LC3_ID,
|
||
|
- LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 3u, 26,
|
||
|
+ LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 26,
|
||
|
240),
|
||
|
UTIL_IOV_INIT()),
|
||
|
|
||
|
@@ -1198,7 +1196,7 @@ static const struct capabilities {
|
||
|
* Frame length: 26-240
|
||
|
*/
|
||
|
CODEC_CAPABILITIES("pac_src/lc3", PAC_SOURCE_UUID, LC3_ID,
|
||
|
- LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 3u, 26,
|
||
|
+ LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 26,
|
||
|
240),
|
||
|
UTIL_IOV_INIT()),
|
||
|
|
||
|
@@ -1210,7 +1208,7 @@ static const struct capabilities {
|
||
|
* Frame length: 26-240
|
||
|
*/
|
||
|
CODEC_CAPABILITIES("bcaa/lc3", BCAA_SERVICE_UUID, LC3_ID,
|
||
|
- LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 3u, 26,
|
||
|
+ LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 26,
|
||
|
240),
|
||
|
UTIL_IOV_INIT()),
|
||
|
|
||
|
@@ -1222,7 +1220,7 @@ static const struct capabilities {
|
||
|
* Frame length: 26-240
|
||
|
*/
|
||
|
CODEC_CAPABILITIES("baa/lc3", BAA_SERVICE_UUID, LC3_ID,
|
||
|
- LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 3u, 26,
|
||
|
+ LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 26,
|
||
|
240),
|
||
|
UTIL_IOV_INIT()),
|
||
|
};
|
||
|
@@ -3220,6 +3218,7 @@ static void endpoint_locations(const char *input, void *user_data)
|
||
|
struct endpoint *ep = user_data;
|
||
|
char *endptr = NULL;
|
||
|
int value;
|
||
|
+ uint8_t channels;
|
||
|
|
||
|
value = strtol(input, &endptr, 0);
|
||
|
|
||
|
@@ -3230,6 +3229,12 @@ static void endpoint_locations(const char *input, void *user_data)
|
||
|
|
||
|
ep->locations = value;
|
||
|
|
||
|
+ channels = __builtin_popcount(value);
|
||
|
+ /* Automatically set LC3_CHAN_COUNT if only 1 location is supported */
|
||
|
+ if (channels == 1)
|
||
|
+ util_ltv_push(ep->caps, sizeof(channels), LC3_CHAN_COUNT,
|
||
|
+ &channels);
|
||
|
+
|
||
|
bt_shell_prompt_input(ep->path, "Supported Context (value):",
|
||
|
endpoint_supported_context, ep);
|
||
|
}
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From c2312ebe318413f9e72df505fa236024b57429d4 Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Fri, 19 Jul 2024 15:52:29 -0400
|
||
|
Subject: [PATCH 31/46] client/player: Add support to enter alternative preset
|
||
|
|
||
|
This adds support for alternative preset to be entered so when auto
|
||
|
accepting configuration a different preset can be selected following the
|
||
|
order given to endpoint.presets.
|
||
|
---
|
||
|
client/player.c | 120 ++++++++++++++++++++++++++++++++++++++++--------
|
||
|
1 file changed, 101 insertions(+), 19 deletions(-)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index 9334a053d34d..3c3587f2ca3a 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -1230,7 +1230,10 @@ struct codec_preset {
|
||
|
const struct iovec data;
|
||
|
struct bt_bap_qos qos;
|
||
|
uint8_t target_latency;
|
||
|
+ uint32_t chan_alloc;
|
||
|
bool custom;
|
||
|
+ bool alt;
|
||
|
+ struct codec_preset *alt_preset;
|
||
|
};
|
||
|
|
||
|
#define SBC_PRESET(_name, _data) \
|
||
|
@@ -1969,12 +1972,31 @@ static int parse_chan_alloc(DBusMessageIter *iter, uint32_t *location,
|
||
|
if (*channels)
|
||
|
*channels = __builtin_popcount(*location);
|
||
|
return 0;
|
||
|
+ } else if (!strcasecmp(key, "Locations")) {
|
||
|
+ uint32_t tmp;
|
||
|
+
|
||
|
+ if (var != DBUS_TYPE_UINT32)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ dbus_message_iter_get_basic(&value, &tmp);
|
||
|
+ *location &= tmp;
|
||
|
+
|
||
|
+ if (*channels)
|
||
|
+ *channels = __builtin_popcount(*location);
|
||
|
}
|
||
|
|
||
|
dbus_message_iter_next(iter);
|
||
|
}
|
||
|
|
||
|
- return -EINVAL;
|
||
|
+ return *location ? 0 : -EINVAL;
|
||
|
+}
|
||
|
+
|
||
|
+static void ltv_find(size_t i, uint8_t l, uint8_t t, uint8_t *v,
|
||
|
+ void *user_data)
|
||
|
+{
|
||
|
+ bool *found = user_data;
|
||
|
+
|
||
|
+ *found = true;
|
||
|
}
|
||
|
|
||
|
static DBusMessage *endpoint_select_properties_reply(struct endpoint *ep,
|
||
|
@@ -1985,7 +2007,7 @@ static DBusMessage *endpoint_select_properties_reply(struct endpoint *ep,
|
||
|
DBusMessageIter iter, props;
|
||
|
struct endpoint_config *cfg;
|
||
|
struct bt_bap_io_qos *qos;
|
||
|
- uint32_t location = 0;
|
||
|
+ uint32_t location = ep->locations;
|
||
|
uint8_t channels = 1;
|
||
|
|
||
|
if (!preset)
|
||
|
@@ -2006,13 +2028,44 @@ static DBusMessage *endpoint_select_properties_reply(struct endpoint *ep,
|
||
|
dbus_message_iter_recurse(&iter, &props);
|
||
|
|
||
|
if (!parse_chan_alloc(&props, &location, &channels)) {
|
||
|
- uint8_t chan_alloc_ltv[] = {
|
||
|
- 0x05, LC3_CONFIG_CHAN_ALLOC, location & 0xff,
|
||
|
- location >> 8, location >> 16, location >> 24
|
||
|
- };
|
||
|
+ uint32_t chan_alloc = 0;
|
||
|
+ uint8_t type = LC3_CONFIG_CHAN_ALLOC;
|
||
|
+ bool found = false;
|
||
|
+
|
||
|
+ if (preset->chan_alloc & location)
|
||
|
+ chan_alloc = preset->chan_alloc & location;
|
||
|
+ else if (preset->alt_preset &&
|
||
|
+ preset->alt_preset->chan_alloc &
|
||
|
+ location) {
|
||
|
+ chan_alloc = preset->alt_preset->chan_alloc & location;
|
||
|
+ preset = preset->alt_preset;
|
||
|
+
|
||
|
+ /* Copy alternate capabilities */
|
||
|
+ util_iov_free(cfg->caps, 1);
|
||
|
+ cfg->caps = util_iov_dup(&preset->data, 1);
|
||
|
+ cfg->target_latency = preset->target_latency;
|
||
|
+ } else
|
||
|
+ chan_alloc = location;
|
||
|
+
|
||
|
+ /* Check if Channel Allocation is present in caps */
|
||
|
+ util_ltv_foreach(cfg->caps->iov_base, cfg->caps->iov_len,
|
||
|
+ &type, ltv_find, &found);
|
||
|
|
||
|
- util_iov_append(cfg->caps, &chan_alloc_ltv,
|
||
|
+ /* If Channel Allocation has not been set directly via
|
||
|
+ * preset->data then attempt to set it if chan_alloc has been
|
||
|
+ * set.
|
||
|
+ */
|
||
|
+ if (!found && chan_alloc) {
|
||
|
+ uint8_t chan_alloc_ltv[] = {
|
||
|
+ 0x05, LC3_CONFIG_CHAN_ALLOC, chan_alloc & 0xff,
|
||
|
+ chan_alloc >> 8, chan_alloc >> 16,
|
||
|
+ chan_alloc >> 24
|
||
|
+ };
|
||
|
+
|
||
|
+ put_le32(chan_alloc, &chan_alloc_ltv[2]);
|
||
|
+ util_iov_append(cfg->caps, &chan_alloc_ltv,
|
||
|
sizeof(chan_alloc_ltv));
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
/* Copy metadata */
|
||
|
@@ -2035,6 +2088,8 @@ static DBusMessage *endpoint_select_properties_reply(struct endpoint *ep,
|
||
|
|
||
|
dbus_message_iter_init_append(reply, &iter);
|
||
|
|
||
|
+ bt_shell_printf("selecting %s...\n", preset->name);
|
||
|
+
|
||
|
append_properties(&iter, cfg);
|
||
|
|
||
|
free(cfg);
|
||
|
@@ -2098,8 +2153,6 @@ static DBusMessage *endpoint_select_properties(DBusConnection *conn,
|
||
|
if (!reply)
|
||
|
return NULL;
|
||
|
|
||
|
- bt_shell_printf("Auto Accepting using %s...\n", p->name);
|
||
|
-
|
||
|
return reply;
|
||
|
}
|
||
|
|
||
|
@@ -3621,14 +3674,6 @@ add_meta:
|
||
|
endpoint_set_metadata_cfg, cfg);
|
||
|
}
|
||
|
|
||
|
-static void ltv_find(size_t i, uint8_t l, uint8_t t, uint8_t *v,
|
||
|
- void *user_data)
|
||
|
-{
|
||
|
- bool *found = user_data;
|
||
|
-
|
||
|
- *found = true;
|
||
|
-}
|
||
|
-
|
||
|
static void config_endpoint_iso_group(const char *input, void *user_data)
|
||
|
{
|
||
|
struct endpoint_config *cfg = user_data;
|
||
|
@@ -4106,13 +4151,38 @@ static void print_presets(struct preset *preset)
|
||
|
|
||
|
for (i = 0; i < preset->num_presets; i++) {
|
||
|
p = &preset->presets[i];
|
||
|
- bt_shell_printf("%s%s\n", p == preset->default_preset ?
|
||
|
- "*" : "", p->name);
|
||
|
+
|
||
|
+ if (p == preset->default_preset)
|
||
|
+ bt_shell_printf("*%s\n", p->name);
|
||
|
+ else if (preset->default_preset &&
|
||
|
+ p == preset->default_preset->alt_preset)
|
||
|
+ bt_shell_printf("**%s\n", p->name);
|
||
|
+ else
|
||
|
+ bt_shell_printf("%s\n", p->name);
|
||
|
}
|
||
|
|
||
|
queue_foreach(preset->custom, foreach_custom_preset_print, preset);
|
||
|
}
|
||
|
|
||
|
+static void custom_chan_alloc(const char *input, void *user_data)
|
||
|
+{
|
||
|
+ struct codec_preset *p = user_data;
|
||
|
+ char *endptr = NULL;
|
||
|
+
|
||
|
+ p->chan_alloc = strtol(input, &endptr, 0);
|
||
|
+ if (!endptr || *endptr != '\0') {
|
||
|
+ bt_shell_printf("Invalid argument: %s\n", input);
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (p->alt_preset)
|
||
|
+ bt_shell_prompt_input(p->alt_preset->name,
|
||
|
+ "Enter Channel Allocation: ",
|
||
|
+ custom_chan_alloc, p->alt_preset);
|
||
|
+ else
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
||
|
+}
|
||
|
+
|
||
|
static void cmd_presets_endpoint(int argc, char *argv[])
|
||
|
{
|
||
|
struct preset *preset;
|
||
|
@@ -4133,8 +4203,20 @@ static void cmd_presets_endpoint(int argc, char *argv[])
|
||
|
preset->default_preset = default_preset;
|
||
|
|
||
|
if (argc > 4) {
|
||
|
+ struct codec_preset *alt_preset;
|
||
|
struct iovec *iov = (void *)&default_preset->data;
|
||
|
|
||
|
+ /* Check if and alternative preset was given */
|
||
|
+ alt_preset = preset_find_name(preset, argv[4]);
|
||
|
+ if (alt_preset) {
|
||
|
+ default_preset->alt_preset = alt_preset;
|
||
|
+ bt_shell_prompt_input(default_preset->name,
|
||
|
+ "Enter Channel Allocation: ",
|
||
|
+ custom_chan_alloc,
|
||
|
+ default_preset);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
iov->iov_base = str2bytearray(argv[4], &iov->iov_len);
|
||
|
if (!iov->iov_base) {
|
||
|
bt_shell_printf("Invalid configuration %s\n",
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From fcf39175e35ef086ffbe4e84ed6dcd3bf4c0aeea Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Tue, 23 Jul 2024 15:49:58 -0400
|
||
|
Subject: [PATCH 32/46] shared/bap: Fix bt_bap_select with multiple lpacs
|
||
|
|
||
|
When there are multiple local PAC records of the same codec with
|
||
|
different locations only the first was consider, also bt_bap_select
|
||
|
would stop doing location matching early if the location don't match
|
||
|
without considering there could be more remote channels.
|
||
|
---
|
||
|
src/shared/bap.c | 35 ++++++++++++++++++++++++++---------
|
||
|
1 file changed, 26 insertions(+), 9 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index 0aa89c2781ba..499e740c9162 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -3249,25 +3249,32 @@ static void *ltv_merge(struct iovec *data, struct iovec *cont)
|
||
|
return util_iov_append(data, cont->iov_base, cont->iov_len);
|
||
|
}
|
||
|
|
||
|
-static void bap_pac_foreach_channel(size_t i, uint8_t l, uint8_t t, uint8_t *v,
|
||
|
- void *user_data)
|
||
|
+static void bap_pac_chan_add(struct bt_bap_pac *pac, uint8_t count,
|
||
|
+ uint32_t location)
|
||
|
{
|
||
|
- struct bt_bap_pac *pac = user_data;
|
||
|
struct bt_bap_chan *chan;
|
||
|
|
||
|
- if (!v)
|
||
|
- return;
|
||
|
-
|
||
|
if (!pac->channels)
|
||
|
pac->channels = queue_new();
|
||
|
|
||
|
chan = new0(struct bt_bap_chan, 1);
|
||
|
- chan->count = *v;
|
||
|
- chan->location = bt_bap_pac_get_locations(pac) ? : pac->qos.location;
|
||
|
+ chan->count = count;
|
||
|
+ chan->location = location;
|
||
|
|
||
|
queue_push_tail(pac->channels, chan);
|
||
|
}
|
||
|
|
||
|
+static void bap_pac_foreach_channel(size_t i, uint8_t l, uint8_t t, uint8_t *v,
|
||
|
+ void *user_data)
|
||
|
+{
|
||
|
+ struct bt_bap_pac *pac = user_data;
|
||
|
+
|
||
|
+ if (!v)
|
||
|
+ return;
|
||
|
+
|
||
|
+ bap_pac_chan_add(pac, *v, bt_bap_pac_get_locations(pac));
|
||
|
+}
|
||
|
+
|
||
|
static void bap_pac_update_channels(struct bt_bap_pac *pac, struct iovec *data)
|
||
|
{
|
||
|
uint8_t type = 0x03;
|
||
|
@@ -3277,6 +3284,13 @@ static void bap_pac_update_channels(struct bt_bap_pac *pac, struct iovec *data)
|
||
|
|
||
|
util_ltv_foreach(data->iov_base, data->iov_len, &type,
|
||
|
bap_pac_foreach_channel, pac);
|
||
|
+
|
||
|
+ /* If record didn't set a channel count but set a location use that as
|
||
|
+ * channel count.
|
||
|
+ */
|
||
|
+ if (queue_isempty(pac->channels) && pac->qos.location)
|
||
|
+ bap_pac_chan_add(pac, pac->qos.location, pac->qos.location);
|
||
|
+
|
||
|
}
|
||
|
|
||
|
static void bap_pac_merge(struct bt_bap_pac *pac, struct iovec *data,
|
||
|
@@ -3607,6 +3621,9 @@ uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac)
|
||
|
if (!pac)
|
||
|
return 0;
|
||
|
|
||
|
+ if (pac->qos.location)
|
||
|
+ return pac->qos.location;
|
||
|
+
|
||
|
pacs = pac->bdb->pacs;
|
||
|
|
||
|
switch (pac->type) {
|
||
|
@@ -5411,7 +5428,7 @@ int bt_bap_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
|
||
|
|
||
|
/* Try matching the channel location */
|
||
|
if (!(map.location & rc->location))
|
||
|
- break;
|
||
|
+ continue;
|
||
|
|
||
|
lpac->ops->select(lpac, rpac, map.location &
|
||
|
rc->location, &rpac->qos,
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 549d38852f665d8251b2c0c0e8c9f3d5574ac99b Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Mon, 29 Jul 2024 12:37:36 +0100
|
||
|
Subject: [PATCH 33/46] client/player: Fix not setting config target_latency
|
||
|
with edpoint.config
|
||
|
|
||
|
This fixes not setting target_latency with endpoint.config command.
|
||
|
---
|
||
|
client/player.c | 7 ++++---
|
||
|
1 file changed, 4 insertions(+), 3 deletions(-)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index 3c3587f2ca3a..93d6b62e24bf 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -1790,9 +1790,9 @@ static void append_ucast_qos(DBusMessageIter *iter, struct endpoint_config *cfg)
|
||
|
DBUS_TYPE_UINT32, &qos->delay);
|
||
|
|
||
|
if (cfg->target_latency) {
|
||
|
- bt_shell_printf("TargetLatency 0x%02x\n", qos->target_latency);
|
||
|
+ bt_shell_printf("TargetLatency 0x%02x\n", cfg->target_latency);
|
||
|
g_dbus_dict_append_entry(iter, "TargetLatency", DBUS_TYPE_BYTE,
|
||
|
- &qos->target_latency);
|
||
|
+ &cfg->target_latency);
|
||
|
}
|
||
|
|
||
|
append_io_qos(iter, &qos->io_qos);
|
||
|
@@ -3765,6 +3765,7 @@ static void cmd_config_endpoint(int argc, char *argv[])
|
||
|
/* Copy capabilities */
|
||
|
util_iov_append(cfg->caps, preset->data.iov_base,
|
||
|
preset->data.iov_len);
|
||
|
+ cfg->target_latency = preset->target_latency;
|
||
|
|
||
|
/* Set QoS parameters */
|
||
|
cfg->qos = preset->qos;
|
||
|
@@ -3960,7 +3961,7 @@ static void custom_target_latency(const char *input, void *user_data)
|
||
|
else if (!strcasecmp(input, "Balance"))
|
||
|
p->target_latency = 0x02;
|
||
|
else if (!strcasecmp(input, "High"))
|
||
|
- p->target_latency = 0x02;
|
||
|
+ p->target_latency = 0x03;
|
||
|
else {
|
||
|
char *endptr = NULL;
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From d7b7f3a39562ca6341254a711ce079b6b8185cd1 Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Wed, 31 Jul 2024 09:17:06 +0300
|
||
|
Subject: [PATCH 34/46] doc/media: Add 'broadcasting' state and 'Select' method
|
||
|
|
||
|
This adds a new state for transports created by the Broadcast
|
||
|
Sink. Such transports will remain in the 'idle' state until the
|
||
|
user calls 'Select' on them, at which point they will be moved to
|
||
|
'broadcasting'. This allows the user to select the desired BIS as
|
||
|
the audio server automatically acquires transports that are in this
|
||
|
state.
|
||
|
---
|
||
|
doc/org.bluez.MediaTransport.rst | 18 +++++++++++++++++-
|
||
|
1 file changed, 17 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/doc/org.bluez.MediaTransport.rst b/doc/org.bluez.MediaTransport.rst
|
||
|
index 6e95df8f2ee8..c8aca0223d24 100644
|
||
|
--- a/doc/org.bluez.MediaTransport.rst
|
||
|
+++ b/doc/org.bluez.MediaTransport.rst
|
||
|
@@ -7,7 +7,7 @@ BlueZ D-Bus MediaTransport API documentation
|
||
|
--------------------------------------------
|
||
|
|
||
|
:Version: BlueZ
|
||
|
-:Date: September 2023
|
||
|
+:Date: July 2024
|
||
|
:Manual section: 5
|
||
|
:Manual group: Linux System Administration
|
||
|
|
||
|
@@ -51,6 +51,20 @@ void Release()
|
||
|
|
||
|
Releases file descriptor.
|
||
|
|
||
|
+void Select()
|
||
|
+`````````````
|
||
|
+
|
||
|
+ Applicable only for transports created by a broadcast sink. This moves
|
||
|
+ the transport from 'idle' to 'broadcasting'. This allows the user to
|
||
|
+ select which BISes he wishes to sync to via a 2 step process:
|
||
|
+ 1) the user calls this method, changing the transport's state to idle
|
||
|
+ 2) the audio server detects that the transport is in the 'broadcasting'
|
||
|
+ state and automatically acquires it
|
||
|
+
|
||
|
+ Possible Errors:
|
||
|
+
|
||
|
+ :org.bluez.Error.NotAuthorized:
|
||
|
+
|
||
|
Properties
|
||
|
----------
|
||
|
|
||
|
@@ -84,6 +98,8 @@ string State [readonly]
|
||
|
|
||
|
:"idle": not streaming
|
||
|
:"pending": streaming but not acquired
|
||
|
+ :"broadcasting": streaming but not acquired, applicable only for transports
|
||
|
+ created by a broadcast sink
|
||
|
:"active": streaming and acquired
|
||
|
|
||
|
uint16 Delay [readwrite, optional]
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 9357edb87bb98c74677f4c5548a4fe2d589230f8 Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Wed, 31 Jul 2024 09:17:07 +0300
|
||
|
Subject: [PATCH 35/46] transport: Add 'broadcasting' state
|
||
|
|
||
|
This adds a new state for transports created by the Broadcast
|
||
|
Sink device as a result of scanning a Broadcast Source. Such
|
||
|
transports will remain in the 'idle' state until the user
|
||
|
selects them using 'transport.select', at which point they will
|
||
|
be moved to 'broadcasting'.
|
||
|
---
|
||
|
profiles/audio/transport.c | 14 ++++++++++++--
|
||
|
1 file changed, 12 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
|
||
|
index 922911cf3fbc..0a890c0ac5f7 100644
|
||
|
--- a/profiles/audio/transport.c
|
||
|
+++ b/profiles/audio/transport.c
|
||
|
@@ -51,6 +51,10 @@
|
||
|
typedef enum {
|
||
|
TRANSPORT_STATE_IDLE, /* Not acquired and suspended */
|
||
|
TRANSPORT_STATE_PENDING, /* Playing but not acquired */
|
||
|
+ /* Playing but not acquired, applicable only for transports
|
||
|
+ * created by a broadcast sink
|
||
|
+ */
|
||
|
+ TRANSPORT_STATE_BROADCASTING,
|
||
|
TRANSPORT_STATE_REQUESTING, /* Acquire in progress */
|
||
|
TRANSPORT_STATE_ACTIVE, /* Acquired and playing */
|
||
|
TRANSPORT_STATE_SUSPENDING, /* Release in progress */
|
||
|
@@ -59,6 +63,7 @@ typedef enum {
|
||
|
static const char *str_state[] = {
|
||
|
"TRANSPORT_STATE_IDLE",
|
||
|
"TRANSPORT_STATE_PENDING",
|
||
|
+ "TRANSPORT_STATE_BROADCASTING",
|
||
|
"TRANSPORT_STATE_REQUESTING",
|
||
|
"TRANSPORT_STATE_ACTIVE",
|
||
|
"TRANSPORT_STATE_SUSPENDING",
|
||
|
@@ -139,6 +144,8 @@ static const char *state2str(transport_state_t state)
|
||
|
return "idle";
|
||
|
case TRANSPORT_STATE_PENDING:
|
||
|
return "pending";
|
||
|
+ case TRANSPORT_STATE_BROADCASTING:
|
||
|
+ return "broadcasting";
|
||
|
case TRANSPORT_STATE_ACTIVE:
|
||
|
case TRANSPORT_STATE_SUSPENDING:
|
||
|
return "active";
|
||
|
@@ -152,6 +159,7 @@ static gboolean state_in_use(transport_state_t state)
|
||
|
switch (state) {
|
||
|
case TRANSPORT_STATE_IDLE:
|
||
|
case TRANSPORT_STATE_PENDING:
|
||
|
+ case TRANSPORT_STATE_BROADCASTING:
|
||
|
return FALSE;
|
||
|
case TRANSPORT_STATE_REQUESTING:
|
||
|
case TRANSPORT_STATE_ACTIVE:
|
||
|
@@ -679,7 +687,8 @@ static DBusMessage *try_acquire(DBusConnection *conn, DBusMessage *msg,
|
||
|
if (transport->state >= TRANSPORT_STATE_REQUESTING)
|
||
|
return btd_error_not_authorized(msg);
|
||
|
|
||
|
- if (transport->state != TRANSPORT_STATE_PENDING)
|
||
|
+ if ((transport->state != TRANSPORT_STATE_PENDING) &&
|
||
|
+ (transport->state != TRANSPORT_STATE_BROADCASTING))
|
||
|
return btd_error_not_available(msg);
|
||
|
|
||
|
owner = media_owner_create(msg);
|
||
|
@@ -1281,7 +1290,8 @@ static void transport_update_playing(struct media_transport *transport,
|
||
|
str_state[transport->state], playing);
|
||
|
|
||
|
if (playing == FALSE) {
|
||
|
- if (transport->state == TRANSPORT_STATE_PENDING)
|
||
|
+ if ((transport->state == TRANSPORT_STATE_PENDING) ||
|
||
|
+ (transport->state == TRANSPORT_STATE_BROADCASTING))
|
||
|
transport_set_state(transport, TRANSPORT_STATE_IDLE);
|
||
|
else if (transport->state == TRANSPORT_STATE_ACTIVE) {
|
||
|
/* Remove owner */
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 083d1a7b66b5c495d2545670d5d255aef340dbf9 Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Wed, 31 Jul 2024 09:17:08 +0300
|
||
|
Subject: [PATCH 36/46] transport: Add 'Select' method
|
||
|
|
||
|
This adds the 'Select' method for Broadcast transports. It's role
|
||
|
is to change the transport's state from idle to broadcasting. This
|
||
|
allows the user to select the desired stream when running the setup
|
||
|
with PipeWire since it acquires any transport that is broadcasting.
|
||
|
---
|
||
|
profiles/audio/transport.c | 24 ++++++++++++++++++++++++
|
||
|
1 file changed, 24 insertions(+)
|
||
|
|
||
|
diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
|
||
|
index 0a890c0ac5f7..bf2215a0f725 100644
|
||
|
--- a/profiles/audio/transport.c
|
||
|
+++ b/profiles/audio/transport.c
|
||
|
@@ -972,6 +972,9 @@ static gboolean get_endpoint(const GDBusPropertyTable *property,
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
+static DBusMessage *select_transport(DBusConnection *conn, DBusMessage *msg,
|
||
|
+ void *data);
|
||
|
+
|
||
|
static const GDBusMethodTable transport_methods[] = {
|
||
|
{ GDBUS_ASYNC_METHOD("Acquire",
|
||
|
NULL,
|
||
|
@@ -984,6 +987,8 @@ static const GDBusMethodTable transport_methods[] = {
|
||
|
{ "mtu_w", "q" }),
|
||
|
try_acquire) },
|
||
|
{ GDBUS_ASYNC_METHOD("Release", NULL, NULL, release) },
|
||
|
+ { GDBUS_ASYNC_METHOD("Select",
|
||
|
+ NULL, NULL, select_transport) },
|
||
|
{ },
|
||
|
};
|
||
|
|
||
|
@@ -1302,6 +1307,25 @@ static void transport_update_playing(struct media_transport *transport,
|
||
|
transport_set_state(transport, TRANSPORT_STATE_PENDING);
|
||
|
}
|
||
|
|
||
|
+static DBusMessage *select_transport(DBusConnection *conn, DBusMessage *msg,
|
||
|
+ void *data)
|
||
|
+{
|
||
|
+ struct media_transport *transport = data;
|
||
|
+
|
||
|
+ if (transport->owner != NULL)
|
||
|
+ return btd_error_not_authorized(msg);
|
||
|
+
|
||
|
+ if (transport->state >= TRANSPORT_STATE_REQUESTING)
|
||
|
+ return btd_error_not_authorized(msg);
|
||
|
+
|
||
|
+ if (!strcmp(media_endpoint_get_uuid(transport->endpoint),
|
||
|
+ BAA_SERVICE_UUID)) {
|
||
|
+ transport_update_playing(transport, TRUE);
|
||
|
+ }
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
static void sink_state_changed(struct btd_service *service,
|
||
|
sink_state_t old_state,
|
||
|
sink_state_t new_state,
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 61e16e3b831754368599fc619ddac31f0db48571 Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Wed, 31 Jul 2024 09:17:09 +0300
|
||
|
Subject: [PATCH 37/46] client/player: Expose transport 'Select' method to the
|
||
|
user
|
||
|
|
||
|
This exposes the 'Select' method for Broadcast transports. This
|
||
|
allows the user to select the desired stream when running the setup
|
||
|
with PipeWire since it acquires any transport that is broadcasting.
|
||
|
---
|
||
|
client/player.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
1 file changed, 52 insertions(+)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index 93d6b62e24bf..c36e7ff4851b 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -4766,6 +4766,23 @@ static void acquire_reply(DBusMessage *message, void *user_data)
|
||
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
+static void select_reply(DBusMessage *message, void *user_data)
|
||
|
+{
|
||
|
+ DBusError error;
|
||
|
+
|
||
|
+ dbus_error_init(&error);
|
||
|
+
|
||
|
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
|
||
|
+ bt_shell_printf("Failed to select: %s\n", error.name);
|
||
|
+ dbus_error_free(&error);
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+
|
||
|
+ bt_shell_printf("Select successful");
|
||
|
+
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
||
|
+}
|
||
|
+
|
||
|
static void prompt_acquire(const char *input, void *user_data)
|
||
|
{
|
||
|
GDBusProxy *proxy = user_data;
|
||
|
@@ -4987,6 +5004,38 @@ static void cmd_acquire_transport(int argc, char *argv[])
|
||
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
||
|
}
|
||
|
|
||
|
+static void transport_select(GDBusProxy *proxy, bool prompt)
|
||
|
+{
|
||
|
+ if (!g_dbus_proxy_method_call(proxy, "Select", NULL,
|
||
|
+ select_reply, proxy, NULL)) {
|
||
|
+ bt_shell_printf("Failed select transport\n");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void cmd_select_transport(int argc, char *argv[])
|
||
|
+{
|
||
|
+ GDBusProxy *proxy;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 1; i < argc; i++) {
|
||
|
+ proxy = g_dbus_proxy_lookup(transports, NULL, argv[i],
|
||
|
+ BLUEZ_MEDIA_TRANSPORT_INTERFACE);
|
||
|
+ if (!proxy) {
|
||
|
+ bt_shell_printf("Transport %s not found\n", argv[i]);
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (find_transport(proxy)) {
|
||
|
+ bt_shell_printf("Transport %s already acquired\n",
|
||
|
+ argv[i]);
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+
|
||
|
+ transport_select(proxy, false);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
static void release_reply(DBusMessage *message, void *user_data)
|
||
|
{
|
||
|
struct transport *transport = user_data;
|
||
|
@@ -5415,6 +5464,9 @@ static const struct bt_shell_menu transport_menu = {
|
||
|
{ "volume", "<transport> [value]", cmd_volume_transport,
|
||
|
"Get/Set transport volume",
|
||
|
transport_generator },
|
||
|
+ { "select", "<transport> [transport1...]", cmd_select_transport,
|
||
|
+ "Select Transport",
|
||
|
+ transport_generator },
|
||
|
{} },
|
||
|
};
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 53a4078cb350f630b19f7fe6ea32dd4e1c01b7bb Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Wed, 31 Jul 2024 09:17:10 +0300
|
||
|
Subject: [PATCH 38/46] transport: Broadcast sink: wait for user to select
|
||
|
transport
|
||
|
|
||
|
This changes the flow for transports created on broadcast sink side.
|
||
|
Transports are not automatically changed to pending anymore, instead
|
||
|
the user must first run transport.select on them which updates the
|
||
|
state to 'broadcasting'. This allows for the selection of the desired
|
||
|
stream when running the setup with PipeWire, which acquires any transport
|
||
|
that is broadcasting.
|
||
|
---
|
||
|
profiles/audio/transport.c | 15 +++++++++------
|
||
|
1 file changed, 9 insertions(+), 6 deletions(-)
|
||
|
|
||
|
diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
|
||
|
index bf2215a0f725..80e4f564c861 100644
|
||
|
--- a/profiles/audio/transport.c
|
||
|
+++ b/profiles/audio/transport.c
|
||
|
@@ -1303,8 +1303,14 @@ static void transport_update_playing(struct media_transport *transport,
|
||
|
if (transport->owner != NULL)
|
||
|
media_transport_remove_owner(transport);
|
||
|
}
|
||
|
- } else if (transport->state == TRANSPORT_STATE_IDLE)
|
||
|
- transport_set_state(transport, TRANSPORT_STATE_PENDING);
|
||
|
+ } else if (transport->state == TRANSPORT_STATE_IDLE) {
|
||
|
+ if (!strcmp(media_endpoint_get_uuid(transport->endpoint),
|
||
|
+ BAA_SERVICE_UUID))
|
||
|
+ transport_set_state(transport,
|
||
|
+ TRANSPORT_STATE_BROADCASTING);
|
||
|
+ else
|
||
|
+ transport_set_state(transport, TRANSPORT_STATE_PENDING);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
static DBusMessage *select_transport(DBusConnection *conn, DBusMessage *msg,
|
||
|
@@ -1686,10 +1692,7 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
|
||
|
bap_update_qos(transport);
|
||
|
else if (bt_bap_stream_io_dir(stream) != BT_BAP_BCAST_SOURCE)
|
||
|
bap_update_bcast_qos(transport);
|
||
|
- if (bt_bap_stream_io_dir(stream) == BT_BAP_BCAST_SOURCE)
|
||
|
- transport_update_playing(transport, TRUE);
|
||
|
- else
|
||
|
- transport_update_playing(transport, FALSE);
|
||
|
+ transport_update_playing(transport, FALSE);
|
||
|
return;
|
||
|
case BT_BAP_STREAM_STATE_DISABLING:
|
||
|
return;
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From c7e79fa8bfffff1c7b76cd32ff925ab4613ceb45 Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Wed, 31 Jul 2024 09:17:11 +0300
|
||
|
Subject: [PATCH 39/46] doc/media: Add 'Unselect' method
|
||
|
|
||
|
This adds the documentation for a new method, exclusive to transports
|
||
|
created by the Broadcast Sink. It would allow the user to terminate the
|
||
|
sync to a BIS, via a 2 step process. The first step is the call to this
|
||
|
method, which changes the transport's state to idle, with the second step
|
||
|
being done by the audio server which detects this change and releases
|
||
|
the transport.
|
||
|
---
|
||
|
doc/org.bluez.MediaTransport.rst | 15 ++++++++++++++-
|
||
|
1 file changed, 14 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/doc/org.bluez.MediaTransport.rst b/doc/org.bluez.MediaTransport.rst
|
||
|
index c8aca0223d24..eb3e04ae25c6 100644
|
||
|
--- a/doc/org.bluez.MediaTransport.rst
|
||
|
+++ b/doc/org.bluez.MediaTransport.rst
|
||
|
@@ -57,7 +57,7 @@ void Select()
|
||
|
Applicable only for transports created by a broadcast sink. This moves
|
||
|
the transport from 'idle' to 'broadcasting'. This allows the user to
|
||
|
select which BISes he wishes to sync to via a 2 step process:
|
||
|
- 1) the user calls this method, changing the transport's state to idle
|
||
|
+ 1) the user calls the method, changing the transport's state to broadcasting
|
||
|
2) the audio server detects that the transport is in the 'broadcasting'
|
||
|
state and automatically acquires it
|
||
|
|
||
|
@@ -65,6 +65,19 @@ void Select()
|
||
|
|
||
|
:org.bluez.Error.NotAuthorized:
|
||
|
|
||
|
+void Unselect()
|
||
|
+```````````````
|
||
|
+
|
||
|
+ Applicable only for transports created by a broadcast sink. This moves
|
||
|
+ the transport from 'broadcasting' or 'active' to 'idle'. This allows the
|
||
|
+ user to terminate the sync to a BIS to via a 2 step process:
|
||
|
+ 1) the user calls this method, changing the transport's state to idle
|
||
|
+ 2) the audio server detects this event and releases the transport
|
||
|
+
|
||
|
+ Possible Errors:
|
||
|
+
|
||
|
+ :org.bluez.Error.NotAuthorized:
|
||
|
+
|
||
|
Properties
|
||
|
----------
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 6ee75c3ec383c664cd7e7be02e951999758a6c4f Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Wed, 31 Jul 2024 09:17:12 +0300
|
||
|
Subject: [PATCH 40/46] transport: Add 'Unselect' method
|
||
|
|
||
|
This adds a new method, exclusive to transports created by the Broadcast
|
||
|
Sink. It allows the user to terminate the sync to a BIS, via a 2 step
|
||
|
process. The first step is the call to this method, which changes the
|
||
|
transport's state to idle, with the second step being done by the audio
|
||
|
server which detects this change and releases the transport.
|
||
|
---
|
||
|
profiles/audio/transport.c | 41 +++++++++++++++++++++++++++++++-------
|
||
|
1 file changed, 34 insertions(+), 7 deletions(-)
|
||
|
|
||
|
diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
|
||
|
index 80e4f564c861..3001457943ac 100644
|
||
|
--- a/profiles/audio/transport.c
|
||
|
+++ b/profiles/audio/transport.c
|
||
|
@@ -975,6 +975,9 @@ static gboolean get_endpoint(const GDBusPropertyTable *property,
|
||
|
static DBusMessage *select_transport(DBusConnection *conn, DBusMessage *msg,
|
||
|
void *data);
|
||
|
|
||
|
+static DBusMessage *unselect_transport(DBusConnection *conn, DBusMessage *msg,
|
||
|
+ void *data);
|
||
|
+
|
||
|
static const GDBusMethodTable transport_methods[] = {
|
||
|
{ GDBUS_ASYNC_METHOD("Acquire",
|
||
|
NULL,
|
||
|
@@ -989,6 +992,8 @@ static const GDBusMethodTable transport_methods[] = {
|
||
|
{ GDBUS_ASYNC_METHOD("Release", NULL, NULL, release) },
|
||
|
{ GDBUS_ASYNC_METHOD("Select",
|
||
|
NULL, NULL, select_transport) },
|
||
|
+ { GDBUS_ASYNC_METHOD("Unselect",
|
||
|
+ NULL, NULL, unselect_transport) },
|
||
|
{ },
|
||
|
};
|
||
|
|
||
|
@@ -1295,13 +1300,22 @@ static void transport_update_playing(struct media_transport *transport,
|
||
|
str_state[transport->state], playing);
|
||
|
|
||
|
if (playing == FALSE) {
|
||
|
- if ((transport->state == TRANSPORT_STATE_PENDING) ||
|
||
|
- (transport->state == TRANSPORT_STATE_BROADCASTING))
|
||
|
- transport_set_state(transport, TRANSPORT_STATE_IDLE);
|
||
|
- else if (transport->state == TRANSPORT_STATE_ACTIVE) {
|
||
|
- /* Remove owner */
|
||
|
- if (transport->owner != NULL)
|
||
|
- media_transport_remove_owner(transport);
|
||
|
+ if (!strcmp(media_endpoint_get_uuid(transport->endpoint),
|
||
|
+ BCAA_SERVICE_UUID)) {
|
||
|
+ if ((transport->state ==
|
||
|
+ TRANSPORT_STATE_BROADCASTING) ||
|
||
|
+ (transport->state == TRANSPORT_STATE_ACTIVE))
|
||
|
+ transport_set_state(transport,
|
||
|
+ TRANSPORT_STATE_IDLE);
|
||
|
+ } else {
|
||
|
+ if (transport->state == TRANSPORT_STATE_PENDING)
|
||
|
+ transport_set_state(transport,
|
||
|
+ TRANSPORT_STATE_IDLE);
|
||
|
+ else if (transport->state == TRANSPORT_STATE_ACTIVE) {
|
||
|
+ /* Remove owner */
|
||
|
+ if (transport->owner != NULL)
|
||
|
+ media_transport_remove_owner(transport);
|
||
|
+ }
|
||
|
}
|
||
|
} else if (transport->state == TRANSPORT_STATE_IDLE) {
|
||
|
if (!strcmp(media_endpoint_get_uuid(transport->endpoint),
|
||
|
@@ -1332,6 +1346,19 @@ static DBusMessage *select_transport(DBusConnection *conn, DBusMessage *msg,
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
+static DBusMessage *unselect_transport(DBusConnection *conn, DBusMessage *msg,
|
||
|
+ void *data)
|
||
|
+{
|
||
|
+ struct media_transport *transport = data;
|
||
|
+
|
||
|
+ if (!strcmp(media_endpoint_get_uuid(transport->endpoint),
|
||
|
+ BAA_SERVICE_UUID)) {
|
||
|
+ transport_update_playing(transport, FALSE);
|
||
|
+ }
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
static void sink_state_changed(struct btd_service *service,
|
||
|
sink_state_t old_state,
|
||
|
sink_state_t new_state,
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 827416638289d901fe5b2bc747fc33cff8b7db99 Mon Sep 17 00:00:00 2001
|
||
|
From: Vlad Pruteanu <vlad.pruteanu@nxp.com>
|
||
|
Date: Wed, 31 Jul 2024 09:17:13 +0300
|
||
|
Subject: [PATCH 41/46] client/player: Expose transport 'Unselect' method to
|
||
|
the user
|
||
|
|
||
|
This exposes the 'Unselect' method for Broadcast transports. This
|
||
|
allows the user to terminate the sync to a specific BIS, via a 2
|
||
|
step process. The first step is the call to this method, which
|
||
|
changes the transport's state to idle, with the second step being
|
||
|
done by the audio server which detects this change and releases
|
||
|
the transport.
|
||
|
---
|
||
|
client/player.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
1 file changed, 48 insertions(+)
|
||
|
|
||
|
diff --git a/client/player.c b/client/player.c
|
||
|
index c36e7ff4851b..f1cd909663eb 100644
|
||
|
--- a/client/player.c
|
||
|
+++ b/client/player.c
|
||
|
@@ -4783,6 +4783,24 @@ static void select_reply(DBusMessage *message, void *user_data)
|
||
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
||
|
}
|
||
|
|
||
|
+static void unselect_reply(DBusMessage *message, void *user_data)
|
||
|
+{
|
||
|
+ DBusError error;
|
||
|
+
|
||
|
+ dbus_error_init(&error);
|
||
|
+
|
||
|
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
|
||
|
+ bt_shell_printf("Failed to unselect: %s\n", error.name);
|
||
|
+ dbus_error_free(&error);
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+
|
||
|
+ bt_shell_printf("Select successful");
|
||
|
+
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
static void prompt_acquire(const char *input, void *user_data)
|
||
|
{
|
||
|
GDBusProxy *proxy = user_data;
|
||
|
@@ -5013,6 +5031,16 @@ static void transport_select(GDBusProxy *proxy, bool prompt)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+static void transport_unselect(GDBusProxy *proxy, bool prompt)
|
||
|
+{
|
||
|
+ if (!g_dbus_proxy_method_call(proxy, "Unselect", NULL,
|
||
|
+ unselect_reply, proxy, NULL)) {
|
||
|
+ bt_shell_printf("Failed unselect transport\n");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
static void cmd_select_transport(int argc, char *argv[])
|
||
|
{
|
||
|
GDBusProxy *proxy;
|
||
|
@@ -5036,6 +5064,23 @@ static void cmd_select_transport(int argc, char *argv[])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+static void cmd_unselect_transport(int argc, char *argv[])
|
||
|
+{
|
||
|
+ GDBusProxy *proxy;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 1; i < argc; i++) {
|
||
|
+ proxy = g_dbus_proxy_lookup(transports, NULL, argv[i],
|
||
|
+ BLUEZ_MEDIA_TRANSPORT_INTERFACE);
|
||
|
+ if (!proxy) {
|
||
|
+ bt_shell_printf("Transport %s not found\n", argv[i]);
|
||
|
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+
|
||
|
+ transport_unselect(proxy, false);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
static void release_reply(DBusMessage *message, void *user_data)
|
||
|
{
|
||
|
struct transport *transport = user_data;
|
||
|
@@ -5467,6 +5512,9 @@ static const struct bt_shell_menu transport_menu = {
|
||
|
{ "select", "<transport> [transport1...]", cmd_select_transport,
|
||
|
"Select Transport",
|
||
|
transport_generator },
|
||
|
+ { "unselect", "<transport> [transport1...]", cmd_unselect_transport,
|
||
|
+ "Unselect Transport",
|
||
|
+ transport_generator },
|
||
|
{} },
|
||
|
};
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 720e8ec9760b8d8bfb565e535bd311bbc8273a76 Mon Sep 17 00:00:00 2001
|
||
|
From: Alexander Ganslandt <alexander.ganslandt@axis.com>
|
||
|
Date: Wed, 31 Jul 2024 12:23:21 +0200
|
||
|
Subject: [PATCH 42/46] client/gatt: Set handle before calling print functions
|
||
|
|
||
|
The print functions (print_service, print_chrc and print_desc) all print
|
||
|
the handle, but the handle is never set in the struct object. This
|
||
|
results in the handle always printing as 0x0000. Set the handle before
|
||
|
calling the print function.
|
||
|
---
|
||
|
client/gatt.c | 21 +++++++++++++++++++++
|
||
|
1 file changed, 21 insertions(+)
|
||
|
|
||
|
diff --git a/client/gatt.c b/client/gatt.c
|
||
|
index e1d2b545d691..4dac8859060b 100644
|
||
|
--- a/client/gatt.c
|
||
|
+++ b/client/gatt.c
|
||
|
@@ -165,6 +165,7 @@ static void print_service_proxy(GDBusProxy *proxy, const char *description)
|
||
|
DBusMessageIter iter;
|
||
|
const char *uuid;
|
||
|
dbus_bool_t primary;
|
||
|
+ uint16_t handle;
|
||
|
|
||
|
if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
|
||
|
return;
|
||
|
@@ -176,10 +177,16 @@ static void print_service_proxy(GDBusProxy *proxy, const char *description)
|
||
|
|
||
|
dbus_message_iter_get_basic(&iter, &primary);
|
||
|
|
||
|
+ if (g_dbus_proxy_get_property(proxy, "Handle", &iter) == FALSE)
|
||
|
+ return;
|
||
|
+
|
||
|
+ dbus_message_iter_get_basic(&iter, &handle);
|
||
|
+
|
||
|
memset(&service, 0, sizeof(service));
|
||
|
service.path = (char *) g_dbus_proxy_get_path(proxy);
|
||
|
service.uuid = (char *) uuid;
|
||
|
service.primary = primary;
|
||
|
+ service.handle = handle;
|
||
|
|
||
|
print_service(&service, description);
|
||
|
}
|
||
|
@@ -253,15 +260,22 @@ static void print_characteristic(GDBusProxy *proxy, const char *description)
|
||
|
struct chrc chrc;
|
||
|
DBusMessageIter iter;
|
||
|
const char *uuid;
|
||
|
+ uint16_t handle;
|
||
|
|
||
|
if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
|
||
|
return;
|
||
|
|
||
|
dbus_message_iter_get_basic(&iter, &uuid);
|
||
|
|
||
|
+ if (g_dbus_proxy_get_property(proxy, "Handle", &iter) == FALSE)
|
||
|
+ return;
|
||
|
+
|
||
|
+ dbus_message_iter_get_basic(&iter, &handle);
|
||
|
+
|
||
|
memset(&chrc, 0, sizeof(chrc));
|
||
|
chrc.path = (char *) g_dbus_proxy_get_path(proxy);
|
||
|
chrc.uuid = (char *) uuid;
|
||
|
+ chrc.handle = handle;
|
||
|
|
||
|
print_chrc(&chrc, description);
|
||
|
}
|
||
|
@@ -347,15 +361,22 @@ static void print_descriptor(GDBusProxy *proxy, const char *description)
|
||
|
struct desc desc;
|
||
|
DBusMessageIter iter;
|
||
|
const char *uuid;
|
||
|
+ uint16_t handle;
|
||
|
|
||
|
if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
|
||
|
return;
|
||
|
|
||
|
dbus_message_iter_get_basic(&iter, &uuid);
|
||
|
|
||
|
+ if (g_dbus_proxy_get_property(proxy, "Handle", &iter) == FALSE)
|
||
|
+ return;
|
||
|
+
|
||
|
+ dbus_message_iter_get_basic(&iter, &handle);
|
||
|
+
|
||
|
memset(&desc, 0, sizeof(desc));
|
||
|
desc.path = (char *) g_dbus_proxy_get_path(proxy);
|
||
|
desc.uuid = (char *) uuid;
|
||
|
+ desc.handle = handle;
|
||
|
|
||
|
print_desc(&desc, description);
|
||
|
}
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 8a708aa5f04613768e903d243a7261efd202ea88 Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Wed, 31 Jul 2024 12:15:47 +0100
|
||
|
Subject: [PATCH 43/46] monitor: Fix crash parsing notification
|
||
|
|
||
|
This fixes the following crash caused by notify callback being NULL:
|
||
|
|
||
|
Jump to the invalid address stated on the next line
|
||
|
at 0x0: ???
|
||
|
by 0x1E8375: print_notify (att.c:5420)
|
||
|
by 0x1E9464: att_multiple_vl_rsp (att.c:5463)
|
||
|
by 0x20D39E: att_packet (att.c:5637)
|
||
|
by 0x1B2054: l2cap_frame (l2cap.c:2567)
|
||
|
by 0x1B4A4D: l2cap_packet (l2cap.c:2708)
|
||
|
by 0x19AD43: packet_hci_acldata (packet.c:12522)
|
||
|
by 0x19CF07: packet_monitor (packet.c:4249)
|
||
|
by 0x152405: data_callback (control.c:973)
|
||
|
by 0x2204F6: mainloop_run (mainloop.c:106)
|
||
|
by 0x221017: mainloop_run_with_signal (mainloop-notify.c:189)
|
||
|
by 0x14F387: main (main.c:298)
|
||
|
Address 0x0 is not stack'd, malloc'd or (recently) free'd
|
||
|
---
|
||
|
monitor/att.c | 3 ++-
|
||
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/monitor/att.c b/monitor/att.c
|
||
|
index a23347ef7ede..73a61658454f 100644
|
||
|
--- a/monitor/att.c
|
||
|
+++ b/monitor/att.c
|
||
|
@@ -4646,7 +4646,8 @@ static void print_notify(const struct l2cap_frame *frame, uint16_t handle,
|
||
|
frame = &clone;
|
||
|
}
|
||
|
|
||
|
- handler->notify(frame);
|
||
|
+ if (handler->notify)
|
||
|
+ handler->notify(frame);
|
||
|
}
|
||
|
|
||
|
static void att_handle_value_notify(const struct l2cap_frame *frame)
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From fe703a0058d8271a259885d3da4e886400cf4245 Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Wed, 31 Jul 2024 12:17:07 +0100
|
||
|
Subject: [PATCH 44/46] shared/bap: Fix not setting metadata
|
||
|
|
||
|
bt_bap_stream_metatada shall not send Update Metadata if the states
|
||
|
don't allow it, instead it shall store it so it can be send later when
|
||
|
enabling the stream.
|
||
|
---
|
||
|
src/shared/bap.c | 13 +++++++++++--
|
||
|
1 file changed, 11 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index 499e740c9162..a7217b4177e7 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -1971,8 +1971,17 @@ static unsigned int bap_ucast_metadata(struct bt_bap_stream *stream,
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
- return bap_stream_metadata(stream, BT_ASCS_METADATA, data, func,
|
||
|
- user_data);
|
||
|
+ switch (bt_bap_stream_get_state(stream)) {
|
||
|
+ /* Valid only if ASE_State field = 0x03 (Enabling) */
|
||
|
+ case BT_BAP_STREAM_STATE_ENABLING:
|
||
|
+ /* or 0x04 (Streaming) */
|
||
|
+ case BT_BAP_STREAM_STATE_STREAMING:
|
||
|
+ return bap_stream_metadata(stream, BT_ASCS_METADATA, data, func,
|
||
|
+ user_data);
|
||
|
+ }
|
||
|
+
|
||
|
+ stream_metadata(stream, data, NULL);
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
static uint8_t stream_release(struct bt_bap_stream *stream, struct iovec *rsp)
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 998104507ba103ae0c83641d381794bf11dd46e0 Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Wed, 31 Jul 2024 12:19:04 +0100
|
||
|
Subject: [PATCH 45/46] bap: Fix not setting metatada
|
||
|
|
||
|
Fix not using bt_bap_stream_metadata when configuring a new stream as
|
||
|
the endpoint/client may have set it.
|
||
|
---
|
||
|
profiles/audio/bap.c | 4 ++++
|
||
|
1 file changed, 4 insertions(+)
|
||
|
|
||
|
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
|
||
|
index 53f430d66171..a2c5a546db47 100644
|
||
|
--- a/profiles/audio/bap.c
|
||
|
+++ b/profiles/audio/bap.c
|
||
|
@@ -1523,6 +1523,10 @@ static void setup_config(void *data, void *user_data)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+ if (setup->metadata && setup->metadata->iov_len)
|
||
|
+ bt_bap_stream_metadata(setup->stream, setup->metadata, NULL,
|
||
|
+ NULL);
|
||
|
+
|
||
|
bt_bap_stream_set_user_data(setup->stream, ep->path);
|
||
|
}
|
||
|
|
||
|
--
|
||
|
2.45.2
|
||
|
|
||
|
|
||
|
From 100c845b2d20e7f4f96b371e044b8b59944230ab Mon Sep 17 00:00:00 2001
|
||
|
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
||
|
Date: Thu, 25 Jul 2024 15:17:39 -0400
|
||
|
Subject: [PATCH 46/46] shared/bap: Fix overwriting sink attribute
|
||
|
|
||
|
When allocating the sink and sink_ccc attribute they were being
|
||
|
overwriten by source and source_ccc attributes.
|
||
|
---
|
||
|
src/shared/bap.c | 4 ++--
|
||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/bap.c b/src/shared/bap.c
|
||
|
index a7217b4177e7..9381ebb39a7c 100644
|
||
|
--- a/src/shared/bap.c
|
||
|
+++ b/src/shared/bap.c
|
||
|
@@ -559,14 +559,14 @@ static struct bt_pacs *pacs_new(struct gatt_db *db)
|
||
|
BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
|
||
|
|
||
|
bt_uuid16_create(&uuid, PAC_SOURCE_CHRC_UUID);
|
||
|
- pacs->sink = gatt_db_service_add_characteristic(pacs->service, &uuid,
|
||
|
+ pacs->source = gatt_db_service_add_characteristic(pacs->service, &uuid,
|
||
|
BT_ATT_PERM_READ,
|
||
|
BT_GATT_CHRC_PROP_READ |
|
||
|
BT_GATT_CHRC_PROP_NOTIFY,
|
||
|
pacs_source_read, NULL,
|
||
|
pacs);
|
||
|
|
||
|
- pacs->sink_ccc = gatt_db_service_add_ccc(pacs->service,
|
||
|
+ pacs->source_ccc = gatt_db_service_add_ccc(pacs->service,
|
||
|
BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
|
||
|
|
||
|
bt_uuid16_create(&uuid, PAC_SOURCE_LOC_CHRC_UUID);
|
||
|
--
|
||
|
2.45.2
|
||
|
|