Linux bluetooth development
 help / color / mirror / Atom feed
From: Kyle Pepper <cochcoder@proton.me>
To: linux-bluetooth@vger.kernel.org
Cc: Marcel Holtmann <marcel@holtmann.org>,
	Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Subject: [PATCH] shared/asha: prime volume before starting audio
Date: Tue, 13 Oct 2026 03:46:27 +0000	[thread overview]
Message-ID: <20261013034613.516771-1-cochcoder@proton.me> (raw)

Some tested renderers remain silent unless the Volume characteristic is
written before START. Prime it with the selected volume and keep the
write best effort.

Test volume-before-START ordering and best-effort failure handling.

Assisted-by: OpenCode:gpt-6.1-sol
---
Submission review notes (not part of the commit message):
Local validation is for base 7428ca2df9356363079db0f48412c20cbdb9471f.
Compatibility with newer upstream tips has not been verified locally.
N8 startup evidence is from the combined downstream stack, not a
volume-only hardware ablation. Native ordering/failure unit tests are
included; other renderer coverage and human contribution review remain.

 .gitignore             |  1 +
 Makefile.am            |  6 +++
 src/shared/asha.c      |  4 ++
 unit/test-asha-start.c | 99 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 110 insertions(+)
 create mode 100644 unit/test-asha-start.c

diff --git a/.gitignore b/.gitignore
index 06b24735df..adff1ea84a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -112,6 +112,7 @@ unit/test-lib
 unit/test-mgmt
 unit/test-uhid
 unit/test-hfp
+unit/test-asha-start
 unit/test-crypto
 unit/test-ecc
 unit/test-hog
diff --git a/Makefile.am b/Makefile.am
index f742458d11..a56d66873b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -706,6 +706,12 @@ unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
 
 unit_tests += unit/test-hfp
 
+unit_tests += unit/test-asha-start
+
+unit_test_asha_start_SOURCES = unit/test-asha-start.c
+unit_test_asha_start_LDADD = src/libshared-glib.la \
+	lib/libbluetooth-internal.la $(GLIB_LIBS)
+
 unit_test_hfp_SOURCES = unit/test-hfp.c
 unit_test_hfp_LDADD = src/libshared-glib.la $(GLIB_LIBS)
 
diff --git a/src/shared/asha.c b/src/shared/asha.c
index 79bb29bf9a..b5e8d67567 100644
--- a/src/shared/asha.c
+++ b/src/shared/asha.c
@@ -262,6 +262,10 @@ unsigned int bt_asha_start(struct bt_asha *asha, bt_asha_cb_t cb,
 		return 0;
 	}
 
+	/* Some renderers require a Volume write before START. */
+	if (!bt_asha_set_volume(asha, asha->volume))
+		DBG("ASHA volume priming failed, continuing with START");
+
 	ret = asha_send_acp(asha, acp_start_cmd, sizeof(acp_start_cmd), cb,
 			user_data);
 	if (ret < 0)
diff --git a/unit/test-asha-start.c b/unit/test-asha-start.c
new file mode 100644
index 0000000000..49df54c1f3
--- /dev/null
+++ b/unit/test-asha-start.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+#include <assert.h>
+
+/* Source-level mocks remain effective with link-time optimization. */
+#define bt_gatt_client_write_without_response test_write_command
+#define bt_gatt_client_write_value test_write_request
+#include "src/shared/asha.c"
+#undef bt_gatt_client_write_without_response
+#undef bt_gatt_client_write_value
+#include "src/shared/tester.h"
+
+static unsigned int commands, requests;
+static bool volume_ok, start_ok;
+static int8_t selected_volume;
+
+void btd_error(uint16_t index, const char *format, ...)
+{
+}
+
+void btd_debug(uint16_t index, const char *format, ...)
+{
+}
+
+unsigned int test_write_command(struct bt_gatt_client *client, uint16_t handle,
+					bool signed_write,
+					const uint8_t *value, uint16_t length)
+{
+	assert(client && handle == 0x82 && !signed_write);
+	assert(length == 1 && (int8_t) value[0] == selected_volume);
+	assert(requests == 0);
+	commands++;
+	return volume_ok;
+}
+
+unsigned int test_write_request(struct bt_gatt_client *client, uint16_t handle,
+				const uint8_t *value, uint16_t length,
+				bt_gatt_client_callback_t callback, void *data,
+				bt_gatt_client_destroy_func_t destroy)
+{
+	assert(client && handle == 0x79);
+	assert(commands == 1 && requests == 0);
+	assert(length == 5 && value[0] == 0x01 && value[1] == 0x01);
+	assert((int8_t) value[3] == selected_volume);
+	assert(callback && data && !destroy);
+	requests++;
+	return start_ok;
+}
+
+static void test_start(const void *user_data)
+{
+	const int8_t volumes[] = { -128, -127, -64, 0 };
+	unsigned int i, fail;
+
+	for (i = 0; i < ARRAY_SIZE(volumes); i++) {
+		for (fail = 0; fail < 2; fail++) {
+			struct bt_asha asha = {
+				.client = (void *) 1, .acp_handle = 0x79,
+				.volume_handle = 0x82, .volume = volumes[i],
+			};
+
+			selected_volume = volumes[i];
+			commands = requests = 0;
+			volume_ok = !fail;
+			start_ok = true;
+			assert(bt_asha_start(&asha, NULL, NULL) == 0);
+			assert(commands == 1 && requests == 1);
+			assert(asha.state == ASHA_STARTING);
+			assert(asha.volume == selected_volume);
+
+			/* A repeated start must not write the volume again. */
+			bt_asha_start(&asha, NULL, NULL);
+			assert(commands == 1 && requests == 1);
+		}
+	}
+
+	{
+		struct bt_asha asha = {
+			.client = (void *) 1, .acp_handle = 0x79,
+			.volume_handle = 0x82, .volume = -64,
+		};
+
+		commands = requests = 0;
+		selected_volume = asha.volume;
+		volume_ok = true;
+		start_ok = false;
+		assert(bt_asha_start(&asha, NULL, NULL) == (unsigned int) -1);
+		assert(asha.state == ASHA_STOPPED);
+		assert(commands == 1 && requests == 1);
+	}
+
+	tester_test_passed();
+}
+
+int main(int argc, char *argv[])
+{
+	tester_init(&argc, &argv);
+	tester_add("ASHA/start/volume", NULL, NULL, test_start, NULL);
+	return tester_run();
+}

base-commit: 7428ca2df9356363079db0f48412c20cbdb9471f


             reply	other threads:[~2026-10-13  3:46 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-13  3:46 Kyle Pepper [this message]
2026-10-13  5:03 ` shared/asha: prime volume before starting audio bluez.test.bot

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=20261013034613.516771-1-cochcoder@proton.me \
    --to=cochcoder@proton.me \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    --cc=marcel@holtmann.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