Linux bluetooth development
 help / color / mirror / Atom feed
* RE: Fix linked transports of an ASE not enabled yet
  2026-11-02 18:12 [PATCH BlueZ v1 1/6] client/scripts: Add bap-duplex-lc3.bt Luiz Augusto von Dentz
@ 2026-11-02 19:43 ` bluez.test.bot
  0 siblings, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-11-02 19:43 UTC (permalink / raw)
  To: linux-bluetooth, luiz.dentz

[-- Attachment #1: Type: text/plain, Size: 2290 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1199382/

---Test result---

Test Summary:
CheckPatch                    PASS      2.68 seconds
GitLint                       FAIL      1.33 seconds
BuildEll                      PASS      20.72 seconds
BluezMake                     PASS      301.89 seconds
MakeCheck                     PASS      14.36 seconds
MakeDistcheck                 PASS      145.70 seconds
CheckValgrind                 PASS      239.45 seconds
CheckSmatch                   WARNING   299.23 seconds
bluezmakeextell               PASS      98.84 seconds
TestFunctional                FAIL      1162.90 seconds
IncrementalBuild              PASS      347.69 seconds
ScanBuild                     PASS      1155.95 seconds

Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,v1,5/6] transport: Don't set linked transports pending before they are enabled

1: T1 Title exceeds max length (85>80): "[BlueZ,v1,5/6] transport: Don't set linked transports pending before they are enabled"
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
src/shared/bap.c:309:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:309:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:309:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structures
##############################
Test: TestFunctional - FAIL
Desc: Run test-functional
Output:
FAIL functional.test_bap::test_bap_unicast_desync[hosts6-vm2]: failed on setup with "NameError: name 'CONFIGURED' is not defined"
FAIL functional.test_bap::test_bap_unicast_duplex_enable_one[hosts6-vm2]: failed on setup with "NameError: name 'CONFIGURED' is not defined"


https://github.com/bluez/bluez/pull/2748

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet
@ 2026-11-02 21:54 Luiz Augusto von Dentz
  2026-11-02 21:54 ` [PATCH BlueZ v2 1/6] client/scripts: Add bap-duplex-lc3.bt Luiz Augusto von Dentz
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-02 21:54 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

When acting as an acceptor, a remote initiator may enable only one ASE of
a bidirectional CIS first, e.g. a phone in a voice call enabling the
Source ASE of a headset before its Sink ASE. Once the CIS is established,
the transport of the Sink ASE, still in QoS Configured, was set pending
along with its link, so an audio server would acquire it and either get
NotAuthorized, failing the working link as well, or have it made active
through the link while its ASE is not enabled.

Likewise, once both ASEs were acquired on their own, disabling one of
them set the transport of the other idle and disabled its ASE as well,
stopping the other direction.

The first patches add a functional test reproducing this, using the
Desynchronized property of an initiator in testing mode to enable and
disable each ASE separately, and the last ones fix it by only updating
the state and owner of a link once its ASE is enabled when acting as a
server, and by leaving links acquired on their own, or desynchronized,
alone when a transport is released.

This depends on "test: functional: wait for BAP transports to be
configured", which bluetoothctl needs before it can acquire the
transports of the test.

Changes in v2:
 - test: functional: Cover enabling one ASE of a bidirectional CIS:
   drive the tests through bluetoothctl (transport.desync, acquire,
   release and show) rather than calling the D-Bus methods directly,
   so the sequence can be reproduced by hand with the same script.
   This also fixes the tests failing on setup with a NameError, as v1
   used a test helper without declaring the dependency above.
 - client/scripts: Add bap-duplex-lc3.bt: describe how to enable and
   disable each direction on its own with bluetoothctl.
 - doc/functional-bap: Document the duplex unicast test cases: list the
   bluetoothctl commands in the steps.
 - No changes to the other patches.

Luiz Augusto von Dentz (6):
  client/scripts: Add bap-duplex-lc3.bt
  doc/functional-bap: Document the duplex unicast test cases
  test: functional: Cover enabling one ASE of a bidirectional CIS
  shared/bap: Add bt_bap_stream_is_client
  transport: Don't set linked transports pending before they are enabled
  transport: Don't disable desynchronized links on release

 client/scripts/bap-duplex-lc3.bt |  53 +++++++++++
 doc/functional-bap.rst           | 112 +++++++++++++++++++++++
 profiles/audio/transport.c       |  95 +++++++++++++++++++-
 src/shared/bap.c                 |   8 ++
 src/shared/bap.h                 |   2 +
 test/functional/test_bap.py      | 147 +++++++++++++++++++++++++++++++
 6 files changed, 414 insertions(+), 3 deletions(-)
 create mode 100644 client/scripts/bap-duplex-lc3.bt

-- 
2.56.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH BlueZ v2 1/6] client/scripts: Add bap-duplex-lc3.bt
  2026-11-02 21:54 [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet Luiz Augusto von Dentz
@ 2026-11-02 21:54 ` Luiz Augusto von Dentz
  2026-11-03  2:04   ` Fix linked transports of an ASE not enabled yet bluez.test.bot
  2026-11-02 21:54 ` [PATCH BlueZ v2 2/6] doc/functional-bap: Document the duplex unicast test cases Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-02 21:54 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Register a PAC Sink and a PAC Source endpoint with LC3, both for Front
Left only, so a single CIS carries both directions, e.g. for a voice
call to a headset with a microphone, and describe how to enable and
disable each direction on its own.

Assisted-by: Claude:claude-opus-5-5
---
 client/scripts/bap-duplex-lc3.bt | 53 ++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 client/scripts/bap-duplex-lc3.bt

diff --git a/client/scripts/bap-duplex-lc3.bt b/client/scripts/bap-duplex-lc3.bt
new file mode 100644
index 000000000000..af82658b5df3
--- /dev/null
+++ b/client/scripts/bap-duplex-lc3.bt
@@ -0,0 +1,53 @@
+power on
+#
+#
+# Register a PAC Sink and a PAC Source endpoint with LC3, both for Front
+# Left only, e.g. a headset with a microphone in a voice call. Run on
+# both sides: the device that pairs is the initiator.
+#
+endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
+# Auto Accept: accept the configuration chosen by the peer
+y
+# Max Transports: no limit
+a
+# Locations: Front Left
+1
+# Supported Context: same as the contexts bluetoothctl registers with
+0x0fff
+# Context
+0x0fff
+# CIG: assigned automatically
+a
+# CIS: assigned automatically
+a
+endpoint.register 00002bcb-0000-1000-8000-00805f9b34fb 0x06
+# Auto Accept: accept the configuration chosen by the peer
+y
+# Max Transports: no limit
+a
+# Locations: Front Left
+1
+# Supported Context: same as the contexts bluetoothctl registers with
+0x000f
+# Context
+0x000f
+# CIG: assigned automatically
+a
+# CIS: assigned automatically
+a
+#
+#
+# With a single location, the stream of each direction uses the same
+# CIS, so the two transports are linked.
+#
+# To enable each direction on its own, as a phone may do in a voice
+# call, run bluetoothd with Testing = true on the initiator and, after
+# pairing, desynchronize the transports and acquire them one at a time:
+#
+# transport.desync /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/pac_sink0/fd0 on
+# transport.acquire /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/pac_source0/fd1
+# transport.acquire /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx/pac_sink0/fd0
+#
+# bluetoothctl on the acceptor acquires each transport once it is
+# pending, i.e. once its ASE is enabled, and transport.release on the
+# initiator disables the ASE of a transport alone.
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH BlueZ v2 2/6] doc/functional-bap: Document the duplex unicast test cases
  2026-11-02 21:54 [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet Luiz Augusto von Dentz
  2026-11-02 21:54 ` [PATCH BlueZ v2 1/6] client/scripts: Add bap-duplex-lc3.bt Luiz Augusto von Dentz
@ 2026-11-02 21:54 ` Luiz Augusto von Dentz
  2026-11-02 21:54 ` [PATCH BlueZ v2 3/6] test: functional: Cover enabling one ASE of a bidirectional CIS Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-02 21:54 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Describe the topology with a stream for each direction over the same
CIS, the test of the Desynchronized property used to enable each
direction separately, and the test of the acceptor when only one of
its ASEs is enabled.

Assisted-by: Claude:claude-opus-5-5
---
 doc/functional-bap.rst | 112 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)

diff --git a/doc/functional-bap.rst b/doc/functional-bap.rst
index 42fa7fda8006..fc367e0f9181 100644
--- a/doc/functional-bap.rst
+++ b/doc/functional-bap.rst
@@ -157,6 +157,118 @@ test_bap_unicast_reconfigure_metadata[empty|media]
 	streams; it does not exercise microphone streams or simultaneous
 	playback and capture.
 
+DUPLEX UNICAST
+==============
+
+Two hosts, connected over LE, with a stream for each direction sharing
+a single CIS, e.g. a voice call to a headset with a microphone:
+
+.. code-block::
+
+	+------------------------+                 +------------------------+
+	| host0                  |      LE ACL     | host1                  |
+	| initiator (central)    | --------------> | acceptor (peripheral)  |
+	| bluetoothd, testing    |                 | bluetoothctl -a auto   |
+	| bluetoothctl -a auto   |                 | bap-duplex-lc3.bt      |
+	| bap-duplex-lc3.bt      |  CIS 0x00 (LC3) | PAC Sink, Front Left   |
+	| PAC Source, Front Left | ==============> |                        |
+	| PAC Sink, Front Left   | <============== | PAC Source, Front Left |
+	+------------------------+                 +------------------------+
+
+	one CIG holding one bidirectional CIS: the Sink ASE and the Source
+	ASE of the acceptor use the same CIS, so the transports of each
+	host are linked
+
+	--> connection is initiated by      ==> audio flows towards
+
+The initiator runs `bluetoothd` in testing mode:
+
+.. code-block::
+
+	[General]
+	Testing = true
+
+which makes the ``Desynchronized`` property of
+**org.bluez.MediaTransport(5)** writable, through ``transport.desync``,
+so each direction can be acquired, and so its ASE enabled, on its own.
+The acceptor does not run in testing mode.
+
+Everything is driven through `bluetoothctl`, see
+**bluetoothctl-transport(1)**, so the sequence can be reproduced by hand
+with the same script. On the initiator, the transport of the remote Sink
+ASE is the one under ``pac_sink``, and the one of the remote Source ASE
+under ``pac_source``. On the acceptor, ``transport.show`` reports the
+UUID of the local PAC of the ASE of each transport.
+
+``client/scripts/bap-duplex-lc3.bt`` on both hosts
+	Registers a PAC Sink endpoint
+	(``00002bc9-0000-1000-8000-00805f9b34fb``) and a PAC Source endpoint
+	(``00002bcb-0000-1000-8000-00805f9b34fb``) with LC3, both with
+	Front Left as their only location, so a single CIS carries both
+	directions. The host that pairs is the initiator.
+
+test_bap_unicast_desync
+-----------------------
+
+:Setup: As above, with both transports created and linked.
+
+:Steps:
+	1. Initiator: ``transport.desync <sink transport> on``.
+	2. Initiator: ``transport.acquire <source transport>``.
+	3. Initiator: ``transport.acquire <sink transport>``.
+
+:Expected:
+	1. ``Desynchronize succeeded``, and ``transport.show`` reports
+	   ``Desynchronized: yes`` for both transports, as it applies to the
+	   links of a transport as well.
+	2. ``Acquire successful: fd <fd> MTU <read>:<write>`` and the
+	   transport moves to ``State: active``, while its link stays in
+	   ``State: idle``.
+	3. The link is acquired on its own and moves to ``State: active``.
+
+:Notes: Checks the mechanism the next test relies on to enable a
+	single ASE of a CIS, so a failure of that one can be told apart
+	from a failure of the initiator to enable the ASEs separately.
+
+test_bap_unicast_duplex_enable_one
+----------------------------------
+
+:Setup: As above, with both transports created and linked, and
+	desynchronized on the initiator.
+
+:Steps:
+	1. Initiator: ``transport.acquire <source transport>`` only, so the
+	   acceptor's Source ASE is enabled and the CIS is established,
+	   while its Sink ASE stays in the QoS Configured state.
+	2. Acceptor: ``transport.show <sink transport>``.
+	3. Initiator: ``transport.acquire <sink transport>``.
+	4. Initiator: ``transport.release <sink transport>``.
+
+:Expected:
+	1. The acceptor's Source ASE transport is acquired by
+	   `bluetoothctl` and moves to ``State: active``.
+	2. The Sink ASE transport stays in ``State: idle``: its ASE has not
+	   been enabled, so it is neither pending nor acquired along with
+	   its link.
+	3. The Sink ASE transport moves to ``State: active``, acquired on
+	   its own once the initiator enables its ASE.
+	4. The Sink ASE transport moves back to ``State: idle`` while the
+	   Source ASE transport stays in ``State: active``, on both hosts:
+	   transports acquired on their own are released on their own.
+
+:Notes: Reproduces a remote initiator, e.g. a phone in a voice call,
+	enabling the Source ASE of a headset before its Sink ASE. As an
+	acceptor cannot enable an ASE itself, acquiring a transport whose
+	ASE is still in QoS is rejected with ``NotAuthorized``. An audio
+	server acquiring every pending transport then fails, and with it
+	the linked transport that was working.
+
+	`bluetoothctl` acquires a transport of its endpoints as soon as it
+	is pending, as an audio server would. Depending on which transport
+	it acquires first, the Sink ASE transport is either rejected or
+	made active through its link, so the test checks the state of the
+	transport rather than the result of the acquisition.
+
 BROADCAST
 =========
 
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH BlueZ v2 3/6] test: functional: Cover enabling one ASE of a bidirectional CIS
  2026-11-02 21:54 [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet Luiz Augusto von Dentz
  2026-11-02 21:54 ` [PATCH BlueZ v2 1/6] client/scripts: Add bap-duplex-lc3.bt Luiz Augusto von Dentz
  2026-11-02 21:54 ` [PATCH BlueZ v2 2/6] doc/functional-bap: Document the duplex unicast test cases Luiz Augusto von Dentz
@ 2026-11-02 21:54 ` Luiz Augusto von Dentz
  2026-11-02 21:54 ` [PATCH BlueZ v2 4/6] shared/bap: Add bt_bap_stream_is_client Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-02 21:54 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Have the initiator, in testing mode, desynchronize its linked
transports and enable the Source ASE of the acceptor alone, as a phone
may do in a voice call, then check that the transport of the Sink ASE,
still in QoS Configured, is neither pending nor acquired along with its
link. Once both are acquired, release the Sink ASE alone and check that
the Source ASE keeps streaming on both sides.

Also check desynchronizing the transports on its own, so a failure to
enable the ASEs separately can be told apart.

Everything is driven through bluetoothctl, so the sequence can be
reproduced by hand with client/scripts/bap-duplex-lc3.bt.

Assisted-by: Claude:claude-opus-5-5
---
 test/functional/test_bap.py | 147 ++++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)

diff --git a/test/functional/test_bap.py b/test/functional/test_bap.py
index 221efd982071..5a96cdba6294 100644
--- a/test/functional/test_bap.py
+++ b/test/functional/test_bap.py
@@ -583,6 +583,153 @@ def test_bap_unicast_reconfigure_metadata(unicast_hosts, metadata):
     )
 
 
+# The initiator runs in testing mode, so its transports can be
+# desynchronized and each direction enabled on its own
+duplex_host_config = host_config(
+    [
+        Bluetoothd(conf=BAP_CONF.replace("[General]\n", "[General]\nTesting = true\n")),
+        Pexpect(),
+    ],
+    [Bluetoothd(conf=BAP_CONF), Pexpect()],
+)
+
+def show_transport(ctl, path):
+    """
+    Properties transport.show reports for the given transport.
+
+    They are indented, unlike the [CHG] lines of other transports that
+    may be printed in between, and a command with a known output is
+    issued after it to tell when everything has been listed.
+    """
+    ctl.send(f"transport.show {path}\nversion\n")
+    ctl.expect(f"Transport {path}", timeout=REPLY_TIMEOUT)
+
+    # Up to the end of the line, or a line still being printed would
+    # match only in part
+    props = {}
+    while True:
+        idx, m = ctl.expect(
+            [r"Version \d", r"\t(UUID|State|Desynchronized): ([^\r\n]*)\r?\n"],
+            timeout=REPLY_TIMEOUT,
+        )
+        if idx == 0:
+            return props
+
+        props[m[0].decode("utf-8")] = m[1].decode("utf-8")
+
+
+def show_state(ctl, path):
+    return show_transport(ctl, path)["State"]
+
+
+@pytest.fixture
+def duplex_hosts(hosts):
+    """
+    Initiator (host0) and acceptor (host1) each with a local PAC Sink and
+    PAC Source endpoint for a single location, paired over LE, with a
+    stream configured for each direction over the same CIS.
+
+    On the initiator, the transport of the remote Sink ASE is under its
+    pac_sink endpoint and the one of the remote Source ASE under its
+    pac_source endpoint. On the acceptor, each transport carries the UUID
+    of the local PAC of its ASE.
+    """
+    host0, host1 = hosts
+
+    initiator = start_bluetoothctl(host0, "bap-duplex-lc3.bt")
+    acceptor = start_bluetoothctl(host1, "bap-duplex-lc3.bt")
+
+    pair_le(host0, initiator, host1, acceptor)
+
+    # bluetoothctl only acquires a transport its local endpoint was
+    # configured with
+    paths = [
+        m[0].decode("utf-8")
+        for m in expect_all(initiator, [CONFIGURED + TRANSPORT_RE] * 2)
+    ]
+    to_sink = next(path for path in paths if "/pac_sink" in path)
+    from_source = next(path for path in paths if "/pac_source" in path)
+
+    # Each transport is reported when created and again under the
+    # SetConfiguration call of its endpoint
+    paths = []
+    while len(paths) < 2:
+        path = expect_all(acceptor, [TRANSPORT_RE])[0][0].decode("utf-8")
+        if path not in paths:
+            paths.append(path)
+    uuids = {path: show_transport(acceptor, path)["UUID"] for path in paths}
+    by_uuid = {
+        uuid: path for path in paths for uuid in (PAC_SINK_UUID, PAC_SOURCE_UUID)
+        if uuid in uuids[path]
+    }
+    assert len(by_uuid) == 2, f"acceptor transports: {uuids}"
+    sink = by_uuid[PAC_SINK_UUID]
+    source = by_uuid[PAC_SOURCE_UUID]
+
+    yield initiator, acceptor, to_sink, from_source, sink, source
+
+
+def desync(initiator, to_sink, from_source):
+    """Desynchronizing a transport desynchronizes its links as well."""
+    initiator.send(f"transport.desync {to_sink} on\n")
+    expect_all(initiator, ["Desynchronize succeeded"])
+
+    for path in (to_sink, from_source):
+        desync = show_transport(initiator, path)["Desynchronized"]
+        assert desync == "yes", f"{path} Desynchronized: {desync}"
+
+
+@duplex_host_config
+def test_bap_unicast_desync(duplex_hosts):
+    initiator, acceptor, to_sink, from_source, sink, source = duplex_hosts
+
+    desync(initiator, to_sink, from_source)
+
+    # Acquiring one transport leaves its link alone
+    initiator.send(f"transport.acquire {from_source}\n")
+    expect_all(initiator, [ACQUIRED, f"Transport {from_source} State: active"])
+    assert show_state(initiator, to_sink) == "idle"
+
+    # The link is acquired on its own, over the CIS already established
+    initiator.send(f"transport.acquire {to_sink}\n")
+    expect_all(initiator, [ACQUIRED, f"Transport {to_sink} State: active"])
+
+
+@duplex_host_config
+def test_bap_unicast_duplex_enable_one(duplex_hosts):
+    initiator, acceptor, to_sink, from_source, sink, source = duplex_hosts
+
+    desync(initiator, to_sink, from_source)
+
+    # Enable the remote Source ASE only, leaving its Sink ASE in QoS,
+    # while the CIS they share is established. bluetoothctl on the
+    # acceptor acquires a transport as soon as it is pending, as an
+    # audio server would.
+    initiator.send(f"transport.acquire {from_source}\n")
+    expect_all(initiator, [ACQUIRED, f"Transport {from_source} State: active"])
+    expect_all(acceptor, [ACQUIRED, f"Transport {source} State: active"])
+
+    # The Sink ASE has not been enabled, so its transport must not be
+    # reported as pending, nor acquired along with the Source one
+    state = show_state(acceptor, sink)
+    assert state == "idle", f"{sink} {state} while in QoS"
+
+    # Once the initiator enables it, it is acquired on its own
+    initiator.send(f"transport.acquire {to_sink}\n")
+    expect_all(initiator, [ACQUIRED, f"Transport {to_sink} State: active"])
+    expect_all(acceptor, [ACQUIRED, f"Transport {sink} State: active"])
+
+    # Disabling the Sink ASE alone leaves the Source one streaming
+    initiator.send(f"transport.release {to_sink}\n")
+    expect_all(initiator, ["Release successful", f"Transport {to_sink} State: idle"])
+    expect_all(acceptor, [f"Transport {sink} State: idle"])
+    time.sleep(1)
+
+    for ctl, path in ((initiator, from_source), (acceptor, source)):
+        state = show_state(ctl, path)
+        assert state == "active", f"{path} {state} once the Sink ASE released"
+
+
 # Broadcast code used by the broadcast scripts, see BCAST_CODE in
 # client/player.c
 BCAST_CODE = (
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH BlueZ v2 4/6] shared/bap: Add bt_bap_stream_is_client
  2026-11-02 21:54 [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2026-11-02 21:54 ` [PATCH BlueZ v2 3/6] test: functional: Cover enabling one ASE of a bidirectional CIS Luiz Augusto von Dentz
@ 2026-11-02 21:54 ` Luiz Augusto von Dentz
  2026-11-02 21:54 ` [PATCH BlueZ v2 5/6] transport: Don't set linked transports pending before they are enabled Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-02 21:54 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Tell whether the stream is handled by the local client, which enables
its ASEs, or by the server, whose ASEs are enabled by the remote.

Assisted-by: Claude:claude-opus-5-5
---
 src/shared/bap.c | 8 ++++++++
 src/shared/bap.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/src/shared/bap.c b/src/shared/bap.c
index 10cc81a51c3e..b1180b532b8d 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -4549,6 +4549,14 @@ struct iovec *bt_bap_pac_get_metadata(struct bt_bap_pac *pac)
 	return pac->metadata;
 }
 
+bool bt_bap_stream_is_client(struct bt_bap_stream *stream)
+{
+	if (!stream)
+		return false;
+
+	return stream->client;
+}
+
 uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream)
 {
 	if (!stream)
diff --git a/src/shared/bap.h b/src/shared/bap.h
index 5bdc5f8dbc34..242bfbb39b30 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -122,6 +122,8 @@ struct iovec *bt_bap_pac_get_metadata(struct bt_bap_pac *pac);
 
 uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream);
 
+bool bt_bap_stream_is_client(struct bt_bap_stream *stream);
+
 struct bt_bap_stream *bt_bap_pac_get_stream(struct bt_bap_pac *pac);
 
 /* Session related function */
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH BlueZ v2 5/6] transport: Don't set linked transports pending before they are enabled
  2026-11-02 21:54 [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2026-11-02 21:54 ` [PATCH BlueZ v2 4/6] shared/bap: Add bt_bap_stream_is_client Luiz Augusto von Dentz
@ 2026-11-02 21:54 ` Luiz Augusto von Dentz
  2026-11-02 21:54 ` [PATCH BlueZ v2 6/6] transport: Don't disable desynchronized links on release Luiz Augusto von Dentz
  2026-11-03 16:30 ` [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet patchwork-bot+bluetooth
  6 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-02 21:54 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

As a server, when the client enables one ASE of a bidirectional CIS
before the other, the transport of the enabled one becomes pending once
the CIS is established, and so did its link, still in QoS Configured.
An audio server would then acquire the link, which was rejected with
NotAuthorized as a server cannot enable an ASE, or acquire the enabled
one and make the link active along with it:

  bap.c:ep_enable() ep 0x5e382ebaba40 id 0x03 dir 0x02
  transport.c:transport_set_state() fd1: IDLE -> PENDING
  transport.c:transport_set_state() fd0: IDLE -> PENDING
  > org.bluez.MediaTransport1.Acquire fd0
  < org.bluez.Error.NotAuthorized

As a server, only update the state and owner of a link once its stream
is enabled, only make it active along with the transport if it was
given its owner, keep the owner of a link acquired on its own, and
don't set a link that is acquired already back to pending.

A link acquired on its own is also released on its own: don't propagate
the state of the transport to it, nor disable it along with the stream,
or disabling one ASE would stop the other direction as well.

Fixes: 47ba235f5a6f ("profiles: Add initial code for bap plugin")
Assisted-by: Claude:claude-opus-5-5
---
 profiles/audio/transport.c | 95 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 92 insertions(+), 3 deletions(-)

diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index e001f73151d9..c6b675f0b6ec 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -727,6 +727,44 @@ static void media_owner_exit(DBusConnection *connection, void *user_data)
 	media_transport_remove_owner(owner->transport);
 }
 
+static bool bap_link_enabled(struct bt_bap_stream *link)
+{
+	/* A client enables its links along with the stream, while a server
+	 * has to wait for the client to enable each of them.
+	 */
+	if (bt_bap_stream_is_client(link))
+		return true;
+
+	switch (bt_bap_stream_get_state(link)) {
+	case BT_BAP_STREAM_STATE_ENABLING:
+	case BT_BAP_STREAM_STATE_STREAMING:
+		return true;
+	}
+
+	return false;
+}
+
+static bool bap_link_independent(struct bt_bap_stream *link,
+						struct media_owner *owner)
+{
+	struct media_transport *transport;
+
+	/* A server has its links enabled separately by the client, so they
+	 * may have been acquired by a different owner.
+	 */
+	if (bt_bap_stream_is_client(link))
+		return false;
+
+	transport = find_transport_by_bap_stream(link);
+
+	return transport && transport->owner && transport->owner != owner;
+}
+
+static bool match_link_independent(const void *data, const void *user_data)
+{
+	return bap_link_independent((void *)data, (void *)user_data);
+}
+
 static void linked_transport_set_owner(void *data, void *user_data)
 {
 	struct bt_bap_stream *stream = data;
@@ -739,6 +777,19 @@ static void linked_transport_set_owner(void *data, void *user_data)
 		return;
 	}
 
+	/* A link that is not enabled cannot be acquired yet, and once it is
+	 * it will be acquired on its own.
+	 */
+	if (!bap_link_enabled(stream))
+		return;
+
+	/* As a server, links are enabled separately by the client, so a link
+	 * acquired already keeps its own owner.
+	 */
+	if (!bt_bap_stream_is_client(stream) && transport->owner &&
+						transport->owner != owner)
+		return;
+
 	/* If the linked transport already has a different owner (e.g. it
 	 * was Acquired separately), tear it down properly instead of
 	 * silently overwriting it. Otherwise the previous owner is
@@ -2209,6 +2260,7 @@ static guint transport_bap_suspend(struct media_transport *transport,
 	struct bap_transport *bap = transport->data;
 	struct queue *links = bt_bap_stream_io_get_links(bap->stream);
 	bt_bap_stream_func_t func = NULL;
+	bool disable_links;
 	guint id;
 
 	if (!bap->stream)
@@ -2225,7 +2277,13 @@ static guint transport_bap_suspend(struct media_transport *transport,
 
 	bap_update_links(transport);
 
-	id = bt_bap_stream_disable(bap->stream, bap->linked, func, owner);
+	/* Don't disable links acquired on their own, they are disabled
+	 * when they are released.
+	 */
+	disable_links = bap->linked &&
+			!queue_find(links, match_link_independent, owner);
+
+	id = bt_bap_stream_disable(bap->stream, disable_links, func, owner);
 
 	if (bt_bap_stream_get_type(bap->stream) == BT_BAP_STREAM_TYPE_BCAST) {
 		if (transport->owner == owner)
@@ -2262,10 +2320,16 @@ static void transport_bap_cancel(struct media_transport *transport, guint id)
 	bt_bap_stream_cancel(bap->stream, id);
 }
 
+struct link_state {
+	transport_state_t state;
+	struct media_owner *owner;
+};
+
 static void link_set_state(void *data, void *user_data)
 {
 	struct bt_bap_stream *stream = data;
-	transport_state_t state = PTR_TO_UINT(user_data);
+	struct link_state *ls = user_data;
+	transport_state_t state = ls->state;
 	struct media_transport *transport;
 
 	transport = find_transport_by_bap_stream(stream);
@@ -2274,6 +2338,30 @@ static void link_set_state(void *data, void *user_data)
 		return;
 	}
 
+	/* A link acquired on its own keeps its state */
+	if (bap_link_independent(stream, ls->owner))
+		return;
+
+	/* Don't bring back a link that is acquired already */
+	if (state == TRANSPORT_STATE_PENDING &&
+			transport->state >= TRANSPORT_STATE_REQUESTING)
+		return;
+
+	/* A link whose stream is not enabled cannot be acquired */
+	if ((state == TRANSPORT_STATE_PENDING ||
+			state == TRANSPORT_STATE_ACTIVE) &&
+			!bap_link_enabled(stream))
+		return;
+
+	/* As a server, a link only becomes active along with the transport
+	 * if it was given its owner, otherwise it may have been enabled in
+	 * the meantime and has to be acquired on its own.
+	 */
+	if (state == TRANSPORT_STATE_ACTIVE &&
+			!bt_bap_stream_is_client(stream) &&
+			transport->owner != ls->owner)
+		return;
+
 	transport_set_state(transport, state);
 }
 
@@ -2281,13 +2369,14 @@ static void transport_bap_set_state(struct media_transport *transport,
 					transport_state_t state)
 {
 	struct bap_transport *bap = transport->data;
+	struct link_state ls = { state, transport->owner };
 
 	if (!bap->linked || bap->desync)
 		return;
 
 	/* Update links */
 	queue_foreach(bt_bap_stream_io_get_links(bap->stream), link_set_state,
-							UINT_TO_PTR(state));
+									&ls);
 }
 
 static void bap_metadata_changed(struct media_transport *transport)
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH BlueZ v2 6/6] transport: Don't disable desynchronized links on release
  2026-11-02 21:54 [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2026-11-02 21:54 ` [PATCH BlueZ v2 5/6] transport: Don't set linked transports pending before they are enabled Luiz Augusto von Dentz
@ 2026-11-02 21:54 ` Luiz Augusto von Dentz
  2026-11-03 16:30 ` [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet patchwork-bot+bluetooth
  6 siblings, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-02 21:54 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Releasing a desynchronized transport also disabled its links, which
are acquired and released on their own, so the other direction of a
CIS stopped while still acquired.

Only disable the links along with the stream when they are
synchronized, as is done when enabling them.

Fixes: 1db06505df5a ("audio: Add ability to desynchronized linked transport")
Assisted-by: Claude:claude-opus-5-5
---
 profiles/audio/transport.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index c6b675f0b6ec..285db0d37554 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -2277,10 +2277,10 @@ static guint transport_bap_suspend(struct media_transport *transport,
 
 	bap_update_links(transport);
 
-	/* Don't disable links acquired on their own, they are disabled
-	 * when they are released.
+	/* Don't disable links that are desynchronized or acquired on their
+	 * own, they are disabled when they are released.
 	 */
-	disable_links = bap->linked &&
+	disable_links = bap->linked && !bap->desync &&
 			!queue_find(links, match_link_independent, owner);
 
 	id = bt_bap_stream_disable(bap->stream, disable_links, func, owner);
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* RE: Fix linked transports of an ASE not enabled yet
  2026-11-02 21:54 ` [PATCH BlueZ v2 1/6] client/scripts: Add bap-duplex-lc3.bt Luiz Augusto von Dentz
@ 2026-11-03  2:04   ` bluez.test.bot
  0 siblings, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-11-03  2:04 UTC (permalink / raw)
  To: linux-bluetooth, luiz.dentz

[-- Attachment #1: Type: text/plain, Size: 2288 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1199535/

---Test result---

Test Summary:
CheckPatch                    PASS      2.53 seconds
GitLint                       FAIL      1.40 seconds
BuildEll                      PASS      19.53 seconds
BluezMake                     PASS      222.87 seconds
MakeCheck                     PASS      13.78 seconds
MakeDistcheck                 PASS      115.34 seconds
CheckValgrind                 PASS      184.26 seconds
CheckSmatch                   WARNING   218.75 seconds
bluezmakeextell               PASS      73.59 seconds
TestFunctional                FAIL      948.33 seconds
IncrementalBuild              PASS      261.44 seconds
ScanBuild                     PASS      808.69 seconds

Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,v2,5/6] transport: Don't set linked transports pending before they are enabled

1: T1 Title exceeds max length (85>80): "[BlueZ,v2,5/6] transport: Don't set linked transports pending before they are enabled"
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
src/shared/bap.c:309:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:309:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:309:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structures
##############################
Test: TestFunctional - FAIL
Desc: Run test-functional
Output:
FAIL functional.test_bap::test_bap_unicast_desync[hosts6-vm2]: failed on setup with "NameError: name 'CONFIGURED' is not defined"
FAIL functional.test_bap::test_bap_unicast_duplex_enable_one[hosts6-vm2]: failed on setup with "NameError: name 'CONFIGURED' is not defined"


https://github.com/bluez/bluez/pull/2749

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet
  2026-11-02 21:54 [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2026-11-02 21:54 ` [PATCH BlueZ v2 6/6] transport: Don't disable desynchronized links on release Luiz Augusto von Dentz
@ 2026-11-03 16:30 ` patchwork-bot+bluetooth
  6 siblings, 0 replies; 10+ messages in thread
From: patchwork-bot+bluetooth @ 2026-11-03 16:30 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Mon,  2 Nov 2026 16:54:51 -0500 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> When acting as an acceptor, a remote initiator may enable only one ASE of
> a bidirectional CIS first, e.g. a phone in a voice call enabling the
> Source ASE of a headset before its Sink ASE. Once the CIS is established,
> the transport of the Sink ASE, still in QoS Configured, was set pending
> along with its link, so an audio server would acquire it and either get
> NotAuthorized, failing the working link as well, or have it made active
> through the link while its ASE is not enabled.
> 
> [...]

Here is the summary with links:
  - [BlueZ,v2,1/6] client/scripts: Add bap-duplex-lc3.bt
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e75d5491cc20
  - [BlueZ,v2,2/6] doc/functional-bap: Document the duplex unicast test cases
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=93c141cf6b3f
  - [BlueZ,v2,3/6] test: functional: Cover enabling one ASE of a bidirectional CIS
    (no matching commit)
  - [BlueZ,v2,4/6] shared/bap: Add bt_bap_stream_is_client
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=a0154796fe33
  - [BlueZ,v2,5/6] transport: Don't set linked transports pending before they are enabled
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=37371e853271
  - [BlueZ,v2,6/6] transport: Don't disable desynchronized links on release
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=f72ff35595a4

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-11-03 16:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02 21:54 [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet Luiz Augusto von Dentz
2026-11-02 21:54 ` [PATCH BlueZ v2 1/6] client/scripts: Add bap-duplex-lc3.bt Luiz Augusto von Dentz
2026-11-03  2:04   ` Fix linked transports of an ASE not enabled yet bluez.test.bot
2026-11-02 21:54 ` [PATCH BlueZ v2 2/6] doc/functional-bap: Document the duplex unicast test cases Luiz Augusto von Dentz
2026-11-02 21:54 ` [PATCH BlueZ v2 3/6] test: functional: Cover enabling one ASE of a bidirectional CIS Luiz Augusto von Dentz
2026-11-02 21:54 ` [PATCH BlueZ v2 4/6] shared/bap: Add bt_bap_stream_is_client Luiz Augusto von Dentz
2026-11-02 21:54 ` [PATCH BlueZ v2 5/6] transport: Don't set linked transports pending before they are enabled Luiz Augusto von Dentz
2026-11-02 21:54 ` [PATCH BlueZ v2 6/6] transport: Don't disable desynchronized links on release Luiz Augusto von Dentz
2026-11-03 16:30 ` [PATCH BlueZ v2 0/6] Fix linked transports of an ASE not enabled yet patchwork-bot+bluetooth
  -- strict thread matches above, loose matches on Subject: below --
2026-11-02 18:12 [PATCH BlueZ v1 1/6] client/scripts: Add bap-duplex-lc3.bt Luiz Augusto von Dentz
2026-11-02 19:43 ` Fix linked transports of an ASE not enabled yet bluez.test.bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox