All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ v2 0/1] audio/avrcp: Add AvrcpVersion config option
@ 2026-09-23  9:18 Pavel Bozhko
  2026-09-23  9:18 ` [PATCH BlueZ v2 1/1] " Pavel Bozhko
  0 siblings, 1 reply; 5+ messages in thread
From: Pavel Bozhko @ 2026-09-23  9:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Pavel Bozhko

Some devices advertise AVRCP 1.3 in SDP but still support absolute
volume (SetAbsoluteVolume and EVENT_VOLUME_CHANGED), introduced in
AVRCP 1.4.  Examples include certain TVs such as LG webOS UM7450PLA
and Xiaomi Mi TV 4A 43 when they act as the audio source.

This patch adds an AvrcpVersion option under [AVRCP] so the local
target version can be raised when the peer SDP record is too old.

Changes in v2:
- Wrap DBG() arguments to stay within 80 columns (checkpatch)

Pavel Bozhko (1):
  audio/avrcp: Add AvrcpVersion config option

 profiles/audio/avrcp.c |  7 +++++++
 src/btd.h              |  1 +
 src/main.c             | 32 ++++++++++++++++++++++++++++++++
 src/main.conf          |  8 ++++++++
 4 files changed, 48 insertions(+)

-- 
2.50.1 (Apple Git-155)

^ permalink raw reply	[flat|nested] 5+ messages in thread
* [PATCH BlueZ 1/1] audio/avrcp: Add AvrcpVersion config option
@ 2026-09-22 15:00 Pavel Bozhko
  2026-09-22 16:34 ` bluez.test.bot
  0 siblings, 1 reply; 5+ messages in thread
From: Pavel Bozhko @ 2026-09-22 15:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Pavel Bozhko

Some devices advertise AVRCP 1.3 in SDP but still support absolute
volume (SetAbsoluteVolume and EVENT_VOLUME_CHANGED), which the
specification introduced in version 1.4.  Examples include certain
TVs such as LG webOS UM7450PLA and Xiaomi Mi TV 4A 43 when acting
as the audio source.

Add an AvrcpVersion option under [AVRCP] and apply it to the target
in target_init(), so the version check in avrcp_volume_supported()
can succeed for such peers.
---
 profiles/audio/avrcp.c |  7 +++++++
 src/btd.h              |  1 +
 src/main.c             | 32 ++++++++++++++++++++++++++++++++
 src/main.conf          |  8 ++++++++
 4 files changed, 48 insertions(+)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index df5f97eaf..3c11ac064 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -4304,6 +4304,13 @@ static void target_init(struct avrcp *session)
 	target = data_init(session, AVRCP_REMOTE_UUID);
 	session->target = target;
 
+	if (btd_opts.avrcp.version &&
+			target->version < btd_opts.avrcp.version) {
+		DBG("Forcing AVRCP version 0x%04x (SDP 0x%04x)",
+					btd_opts.avrcp.version, target->version);
+		target->version = btd_opts.avrcp.version;
+	}
+
 	DBG("%p version 0x%04x", target, target->version);
 
 	btd_service_connecting_complete(service, 0);
diff --git a/src/btd.h b/src/btd.h
index d70276b1d..4ae46100d 100644
--- a/src/btd.h
+++ b/src/btd.h
@@ -124,6 +124,7 @@ struct btd_avdtp_opts {
 struct btd_avrcp_opts {
 	bool		volume_without_target;
 	bool		volume_category;
+	uint16_t	version;
 };
 
 struct btd_advmon_opts {
diff --git a/src/main.c b/src/main.c
index c7a55d30f..763fd2c8d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -181,6 +181,7 @@ static const char *avdtp_options[] = {
 static const char *avrcp_options[] = {
 	"VolumeWithoutTarget",
 	"VolumeCategory",
+	"AvrcpVersion",
 	NULL
 };
 
@@ -1350,6 +1351,35 @@ static void parse_avdtp(GKeyFile *config)
 	parse_avdtp_stream_mode(config);
 }
 
+static void parse_avrcp_version(GKeyFile *config)
+{
+	char *str = NULL;
+	char *endptr = NULL;
+	unsigned int major, minor;
+	unsigned long val;
+	int n = 0;
+
+	if (!parse_config_string(config, "AVRCP", "AvrcpVersion", &str))
+		return;
+
+	if (sscanf(str, "%u.%u%n", &major, &minor, &n) == 2 && !str[n] &&
+					major <= 0xff && minor <= 0xff) {
+		btd_opts.avrcp.version = (major << 8) | minor;
+		g_free(str);
+		return;
+	}
+
+	val = strtoul(str, &endptr, 0);
+	if (endptr && *endptr == '\0' && val > 0 && val <= 0xffff) {
+		btd_opts.avrcp.version = val;
+		g_free(str);
+		return;
+	}
+
+	error("Invalid AVRCP version \"%s\"", str);
+	g_free(str);
+}
+
 static void parse_avrcp(GKeyFile *config)
 {
 	parse_config_bool(config, "AVRCP",
@@ -1358,6 +1388,7 @@ static void parse_avrcp(GKeyFile *config)
 	parse_config_bool(config, "AVRCP",
 		"VolumeCategory",
 		&btd_opts.avrcp.volume_category);
+	parse_avrcp_version(config);
 }
 
 static void parse_advmon(GKeyFile *config)
@@ -1433,6 +1464,7 @@ static void init_defaults(void)
 
 	btd_opts.avrcp.volume_without_target = false;
 	btd_opts.avrcp.volume_category = true;
+	btd_opts.avrcp.version = 0;
 
 	btd_opts.advmon.rssi_sampling_period = 0xFF;
 	btd_opts.csis.encrypt = true;
diff --git a/src/main.conf b/src/main.conf
index 1d8e97dc6..79048ea25 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -380,6 +380,14 @@
 # notifications.
 #VolumeCategory = true
 
+# Override the AVRCP version used for the local Target role.  Some peers
+# report an older profile version (e.g. 1.3) while still supporting features
+# introduced later, such as absolute volume (SetAbsoluteVolume and
+# EVENT_VOLUME_CHANGED, AVRCP 1.4).
+# Possible values: 1.3, 1.4, 1.5, 1.6 or hexadecimal (e.g. 0x0104).
+# Defaults to using the version from the remote SDP record.
+#AvrcpVersion = 1.4
+
 [Policy]
 #
 # The ReconnectUUIDs defines the set of remote services that should try
-- 
2.50.1 (Apple Git-155)


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

end of thread, other threads:[~2026-10-08 16:55 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23  9:18 [PATCH BlueZ v2 0/1] audio/avrcp: Add AvrcpVersion config option Pavel Bozhko
2026-09-23  9:18 ` [PATCH BlueZ v2 1/1] " Pavel Bozhko
2026-09-23 10:47   ` bluez.test.bot
2026-10-08 16:54   ` bluez.test.bot
  -- strict thread matches above, loose matches on Subject: below --
2026-09-22 15:00 [PATCH BlueZ 1/1] " Pavel Bozhko
2026-09-22 16:34 ` bluez.test.bot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.