From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v1 3/6] test: functional: add the true wireless broadcast tests
Date: Mon, 21 Sep 2026 17:01:20 -0400 [thread overview]
Message-ID: <20260921210123.3690449-4-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20260921210123.3690449-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Assisted-by: opencode:claude-opus-5
---
client/scripts/broadcast-sink-left.bt | 23 ++++++
client/scripts/broadcast-sink-right.bt | 23 ++++++
doc/functional-bap.rst | 10 ++-
test/functional/test_bap.py | 104 +++++++++++++++++++++++++
4 files changed, 158 insertions(+), 2 deletions(-)
create mode 100644 client/scripts/broadcast-sink-left.bt
create mode 100644 client/scripts/broadcast-sink-right.bt
diff --git a/client/scripts/broadcast-sink-left.bt b/client/scripts/broadcast-sink-left.bt
new file mode 100644
index 000000000000..d5ad2ed25abb
--- /dev/null
+++ b/client/scripts/broadcast-sink-left.bt
@@ -0,0 +1,23 @@
+power on
+#
+#
+# Register a Broadcast Sink endpoint with LC3 taking a single channel,
+# to act as the left side of a true wireless pair. Each side syncs to
+# the Broadcast Source on its own, with no assistant involved.
+#
+endpoint.register 00001851-0000-1000-8000-00805f9b34fb 0x06
+# Auto Accept: accept the configuration chosen by the peer
+y
+# Max Transports: no limit
+a
+# Locations: Front Left, so only the BIS carrying that channel is synced
+1
+# Supported Context: Media
+4
+#
+#
+# Scan for Broadcast Sources: the sink syncs to the periodic
+# advertising and creates a transport for the BIS matching its own
+# location.
+#
+scan on
diff --git a/client/scripts/broadcast-sink-right.bt b/client/scripts/broadcast-sink-right.bt
new file mode 100644
index 000000000000..58f07dbe67ec
--- /dev/null
+++ b/client/scripts/broadcast-sink-right.bt
@@ -0,0 +1,23 @@
+power on
+#
+#
+# Register a Broadcast Sink endpoint with LC3 taking a single channel,
+# to act as the right side of a true wireless pair. Each side syncs to
+# the Broadcast Source on its own, with no assistant involved.
+#
+endpoint.register 00001851-0000-1000-8000-00805f9b34fb 0x06
+# Auto Accept: accept the configuration chosen by the peer
+y
+# Max Transports: no limit
+a
+# Locations: Front Right, so only the BIS carrying that channel is synced
+2
+# Supported Context: Media
+4
+#
+#
+# Scan for Broadcast Sources: the sink syncs to the periodic
+# advertising and creates a transport for the BIS matching its own
+# location.
+#
+scan on
diff --git a/doc/functional-bap.rst b/doc/functional-bap.rst
index 87917065e1eb..7059e0c735f1 100644
--- a/doc/functional-bap.rst
+++ b/doc/functional-bap.rst
@@ -290,8 +290,9 @@ test_bap_broadcast_earbuds_transport_created
:Steps:
1. Start `bluetoothctl` with the source script on host0.
2. Start `bluetoothctl` with the sink scripts on host1 and host2.
- 3. Each side: ``transport.list``, to check that nothing besides
- the transport of its own BIS was created.
+ 3. Each side: list its **org.bluez.MediaTransport1** objects, to
+ check that nothing besides the transport of its own BIS was
+ created.
:Expected:
1. ``Endpoint /local/endpoint/ep0 registered``, then two
@@ -307,6 +308,11 @@ test_bap_broadcast_earbuds_transport_created
:Notes: The BIS index of the path is what tells the two apart, as each
side only ever sees its own.
+ The objects are listed over D-Bus rather than with
+ ``transport.list``: the endpoint prints the transport it was
+ configured with as well, so a listing cannot be told apart from
+ it in the output.
+
Both transports of the source have to be acquired, as for the CIS
of a CIG: the BIG is only created once every BIS of it is ready.
diff --git a/test/functional/test_bap.py b/test/functional/test_bap.py
index 7bd59777b53b..bfcb43c0ad67 100644
--- a/test/functional/test_bap.py
+++ b/test/functional/test_bap.py
@@ -312,6 +312,20 @@ def remote_transport_properties(remote):
}
+@mainloop_wrap
+def transport_paths():
+ """Paths of every MediaTransport1 object of the host."""
+ objects = dbus.Interface(
+ get_dbus().get_object("org.bluez", "/"),
+ "org.freedesktop.DBus.ObjectManager",
+ ).GetManagedObjects()
+ return sorted(
+ str(path)
+ for path, props in objects.items()
+ if "org.bluez.MediaTransport1" in props
+ )
+
+
def add_preset(ctl, name, props, metadata):
"""Make a custom preset from a transport's codec configuration and QoS."""
@@ -460,6 +474,96 @@ def test_bap_broadcast_transport_acquire(hosts, source_script):
)
+ACQUIRED = r"Acquire successful: fd \d+ MTU \d+:\d+"
+
+# Transport of a given BIS of a broadcast the sink is synced to
+BIS_TRANSPORT = r"Transport (/org/bluez/\S+/bis{}/fd\d+)"
+
+earbuds_host_config = host_config(
+ [Bluetoothd(conf=BAP_CONF), Pexpect()],
+ [Bluetoothd(conf=BAP_CONF), Pexpect()],
+ [Bluetoothd(conf=BAP_CONF), Pexpect()],
+)
+
+
+def start_earbuds_broadcast(hosts):
+ """
+ Source broadcasting one BIS per channel, with the two sides of a
+ true wireless pair scanning for it, each one taking a single
+ channel.
+ """
+ source_host, left_host, right_host = hosts
+
+ source = start_bluetoothctl(source_host, "broadcast-source-2bis.bt")
+
+ # The BIG is only created once every BIS of it is ready, so the
+ # script acquires both transports
+ expect_all(source, [ACQUIRED, ACQUIRED])
+
+ left = start_bluetoothctl(left_host, "broadcast-sink-left.bt")
+ right = start_bluetoothctl(right_host, "broadcast-sink-right.bt")
+
+ return source, left, right
+
+
+def expect_bis_transport(ctl, host, bis):
+ """
+ Transport a side created for the BIS carrying its own channel,
+ checking it is the only one it has.
+ """
+ _, m = ctl.expect(BIS_TRANSPORT.format(bis))
+ transport = m[0].decode("utf-8")
+
+ # Checked over D-Bus rather than with transport.list, as the
+ # endpoint prints the transport it was configured with as well, so
+ # a listing cannot be told apart from it in the output
+ assert host.call(transport_paths) == [transport]
+
+ return transport
+
+
+@earbuds_host_config
+def test_bap_broadcast_earbuds_transport_created(hosts):
+ source_host, left_host, right_host = hosts
+ source, left, right = start_earbuds_broadcast(hosts)
+
+ # Each side syncs to the periodic advertising on its own and only
+ # creates a transport for the BIS whose channel allocation matches
+ # its own location
+ for ctl, host, bis in ((left, left_host, 1), (right, right_host, 2)):
+ transport = expect_bis_transport(ctl, host, bis)
+
+ ctl.send(f"transport.show {transport}\n")
+ ctl.expect(f"Transport {transport}")
+ ctl.expect(r"Codec: 0x06")
+ ctl.expect("State: idle")
+
+
+@earbuds_host_config
+def test_bap_broadcast_earbuds_transport_acquire(hosts):
+ source_host, left_host, right_host = hosts
+ source, left, right = start_earbuds_broadcast(hosts)
+
+ # The two sides sync independently, so each of them is given the
+ # broadcast code of its own, and both are checked
+ for ctl, host, bis in ((left, left_host, 1), (right, right_host, 2)):
+ transport = expect_bis_transport(ctl, host, bis)
+
+ # Selecting the transport syncs to the BIG and starts acquiring
+ ctl.send(f"transport.select {transport}\n")
+ ctl.expect(r"Enter bcode\[value/no\]:")
+ ctl.send(f"{BCAST_CODE}\n")
+
+ expect_all(
+ ctl,
+ [
+ f"Transport {transport} State: broadcasting",
+ ACQUIRED,
+ f"Transport {transport} State: active",
+ ],
+ )
+
+
past_host_config = host_config(
[Bluetoothd(conf=BAP_CONF), Pexpect()],
[Bluetoothd(conf=BAP_CONF), Pexpect()],
--
2.55.0
next prev parent reply other threads:[~2026-09-21 21:01 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 21:01 [PATCH BlueZ v1 0/6] Add true wireless BAP broadcast tests Luiz Augusto von Dentz
2026-09-21 21:01 ` [PATCH BlueZ v1 1/6] doc: describe the true wireless broadcast test cases Luiz Augusto von Dentz
2026-09-21 23:47 ` Add true wireless BAP broadcast tests bluez.test.bot
2026-09-21 21:01 ` [PATCH BlueZ v1 2/6] doc: describe the true wireless broadcast assistant test case Luiz Augusto von Dentz
2026-09-21 21:01 ` Luiz Augusto von Dentz [this message]
2026-09-21 21:01 ` [PATCH BlueZ v1 4/6] bass: keep the push target per MediaAssistant object Luiz Augusto von Dentz
2026-09-21 21:01 ` [PATCH BlueZ v1 5/6] client: connect a device that is already paired Luiz Augusto von Dentz
2026-09-21 21:01 ` [PATCH BlueZ v1 6/6] test: functional: add the true wireless broadcast assistant test Luiz Augusto von Dentz
2026-09-22 15:00 ` [PATCH BlueZ v1 0/6] Add true wireless BAP broadcast tests patchwork-bot+bluetooth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260921210123.3690449-4-luiz.dentz@gmail.com \
--to=luiz.dentz@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox