Skip to contentSkip to conversation

transport: distinguish BAP mic and playback volumes

PATCH Applied Pauli Virtanen 3 participants 5 messages Jan 5 – Jan 8 Bluetooth drivers

lore
Share & tools
lore
#0 lore raw

v2 cover transport: distinguish BAP mic and playback volumes

v2:
- Drop the bt_bap_stream_is_server() function. The direction can be found based on bt_bap_stream_get_dir(), which for BAP Client indicates the remote endpoint, and for BAP Server the local endpoint direction.

Its return value is a bit strange for broadcast, as lpac BCAST_SINK -> dir BCAST_SOURCE.

***

Currently we are confusing VCP and MICP volumes.

We are also mixing up AVRCP and VCP volumes.

As microphone volumes are commonly 100% and sound server may set them, we end up with spurious 100% playback volumes.

Fix this, and also do some cleanup of #ifdefs in the volume code.

Pauli Virtanen (2):
transport: clean up volume set/get for A2DP and VCP
transport: distinguish BAP mic and playback volumes

 profiles/audio/avrcp.c     |  10 +--
 profiles/audio/media.c     |   2 +-
 profiles/audio/media.h     |  10 +++
 profiles/audio/transport.c | 133 +++++++++++++++++++++----------------
 profiles/audio/transport.h |  10 +--
 profiles/audio/vcp.c       |  12 ++--
 profiles/audio/vcp.h       |  21 +++++-
 7 files changed, 121 insertions(+), 77 deletions(-)
Signature · 1 line
2.52.0
#1 lore raw

PATCH v2 1/2 transport: clean up volume set/get for A2DP and VCP

Cleanup uuid comparisons in device transport volume set/get. These are unnecessary because the transport->ops already do the equivalent check.

Use separate functions for set/get AVRCP volume, to avoid mixing up AVRCP and VCP volumes.

For VCP send volume update notifications on all transports, since same volume is listed on all.

To avoid interspersing #ifdefs for A2DP/VCP in this code, define dummy functions in headers that behave accordingly.

Fix the bt_audio_vcp_get/set_volume to properly indicate when VCP is not present.

---
 profiles/audio/avrcp.c     |  10 ++--
 profiles/audio/media.c     |   2 +-
 profiles/audio/media.h     |  10 ++++
 profiles/audio/transport.c | 116 +++++++++++++++++++------------------
 profiles/audio/transport.h |  10 ++--
 profiles/audio/vcp.c       |  12 ++--
 profiles/audio/vcp.h       |  21 ++++++-
 7 files changed, 105 insertions(+), 76 deletions(-)
profiles/audio/avrcp.c +5 -5
index 14889e4b4..724b46c59 100644
@@ -1672,7 +1672,7 @@ static uint8_t avrcp_handle_register_notification(struct avrcp *session,
 		len = 1;
 		break;
 	case AVRCP_EVENT_VOLUME_CHANGED:
-		volume = media_transport_get_device_volume(dev);
+		volume = media_transport_get_a2dp_volume(dev);
 		if (volume < 0)
 			goto err;
 
@@ -1795,7 +1795,7 @@ static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session,
 
 	volume = pdu->params[0] = pdu->params[0] & 0x7F;
 
-	media_transport_update_device_volume(session->dev, volume);
+	media_transport_set_a2dp_volume(session->dev, volume);
 
 	return AVC_CTYPE_ACCEPTED;
 
@@ -3809,7 +3809,7 @@ static void avrcp_volume_changed(struct avrcp *session,
 	volume = pdu->params[1] & 0x7F;
 
 	/* Always attempt to update the transport volume */
-	media_transport_update_device_volume(session->dev, volume);
+	media_transport_set_a2dp_volume(session->dev, volume);
 }
 
 static void avrcp_status_changed(struct avrcp *session,
@@ -4284,7 +4284,7 @@ static void target_init(struct avrcp *session)
 		player->sessions = g_slist_prepend(player->sessions, session);
 
 		init_volume = btd_device_get_volume(session->dev);
-		media_transport_update_device_volume(session->dev, init_volume);
+		media_transport_set_a2dp_volume(session->dev, init_volume);
 	}
 
 	session->supported_events |= (1 << AVRCP_EVENT_STATUS_CHANGED) |
@@ -4646,7 +4646,7 @@ static gboolean avrcp_handle_set_volume(struct avctp *conn, uint8_t code,
 	volume = pdu->params[0] & 0x7F;
 
 	/* Always attempt to update the transport volume */
-	media_transport_update_device_volume(session->dev, volume);
+	media_transport_set_a2dp_volume(session->dev, volume);
 
 	return FALSE;
 }
profiles/audio/media.c +1 -1
index ad9eb7beb..cc0029750 100644
@@ -583,7 +583,7 @@ static gboolean set_configuration(struct media_endpoint *endpoint,
 		return FALSE;
 
 	init_volume = btd_device_get_volume(device);
-	media_transport_update_volume(transport, init_volume);
+	media_transport_set_a2dp_volume(device, init_volume);
 
 	msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
 						MEDIA_ENDPOINT_INTERFACE,
profiles/audio/media.h +10 -0
index 28174a017..1c43075ba 100644
@@ -18,7 +18,17 @@ typedef void (*media_endpoint_cb_t) (struct media_endpoint *endpoint,
 int media_register(struct btd_adapter *btd_adapter);
 void media_unregister(struct btd_adapter *btd_adapter);
 
+#ifdef HAVE_A2DP
 struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint);
+#else
+struct a2dp_sep;
+static inline struct a2dp_sep *media_endpoint_get_sep(
+						struct media_endpoint *endpoint)
+{
+	return NULL;
+}
+#endif
+
 const char *media_endpoint_get_uuid(struct media_endpoint *endpoint);
 bool media_endpoint_get_delay_reporting(struct media_endpoint *endpoint);
 uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint);
profiles/audio/transport.c +59 -57

191 lines not on this page · raw message

profiles/audio/transport.h +5 -5
index 7c107281a..90e079c4c 100644
@@ -21,8 +21,6 @@ void media_transport_destroy(struct media_transport *transport);
 const char *media_transport_get_path(struct media_transport *transport);
 void *media_transport_get_stream(struct media_transport *transport);
 struct btd_device *media_transport_get_dev(struct media_transport *transport);
-int media_transport_get_volume(struct media_transport *transport,
-					int *volume);
 void media_transport_update_delay(struct media_transport *transport,
 							uint16_t delay);
 void media_transport_update_volume(struct media_transport *transport,
@@ -30,7 +28,9 @@ void media_transport_update_volume(struct media_transport *transport,
 void transport_get_properties(struct media_transport *transport,
 							DBusMessageIter *iter);
 
-int media_transport_get_device_volume(struct btd_device *dev);
-void media_transport_update_device_volume(struct btd_device *dev,
-								int volume);
+int media_transport_get_a2dp_volume(struct btd_device *dev);
+void media_transport_set_a2dp_volume(struct btd_device *dev, int volume);
+
+void media_transport_volume_changed(struct btd_device *dev);
+
 const char *media_transport_stream_path(void *stream);
profiles/audio/vcp.c +6 -6
index 277c9bbc3..00ee2b64b 100644
@@ -107,7 +107,7 @@ static void vcp_volume_changed(struct bt_vcp *vcp, uint8_t volume)
 	struct vcp_data *data = queue_find(sessions, match_data, vcp);
 
 	if (data)
-		media_transport_update_device_volume(data->device, volume);
+		media_transport_volume_changed(data->device);
 }
 
 static void vcp_data_add(struct vcp_data *data)
@@ -165,24 +165,24 @@ static void vcp_data_remove(struct vcp_data *data)
 	}
 }
 
-uint8_t bt_audio_vcp_get_volume(struct btd_device *device)
+int bt_audio_vcp_get_volume(struct btd_device *device)
 {
 	struct vcp_data *data = queue_find(sessions, match_device, device);
 
 	if (data)
 		return bt_vcp_get_volume(data->vcp);
 
-	return 0;
+	return -ENODEV;
 }
 
-bool bt_audio_vcp_set_volume(struct btd_device *device, uint8_t volume)
+int bt_audio_vcp_set_volume(struct btd_device *device, uint8_t volume)
 {
 	struct vcp_data *data = queue_find(sessions, match_device, device);
 
 	if (data)
-		return bt_vcp_set_volume(data->vcp, volume);
+		return bt_vcp_set_volume(data->vcp, volume) ? 0 : -EIO;
 
-	return FALSE;
+	return -ENODEV;
 }
 
 static void vcp_remote_client_detached(struct bt_vcp *vcp, void *user_data)
profiles/audio/vcp.h +19 -2
index cf7935d1a..b538cebf0 100644
@@ -8,5 +8,22 @@
  *
  */
 
-uint8_t bt_audio_vcp_get_volume(struct btd_device *device);
-bool bt_audio_vcp_set_volume(struct btd_device *device, uint8_t volume);
+#ifdef HAVE_VCP
+
+int bt_audio_vcp_get_volume(struct btd_device *device);
+int bt_audio_vcp_set_volume(struct btd_device *device, uint8_t volume);
+
+#else
+
+static inline int bt_audio_vcp_get_volume(struct btd_device *device)
+{
+	return -ENODEV;
+}
+
+static inline int bt_audio_vcp_set_volume(struct btd_device *device,
+								uint8_t volume)
+{
+	return -ENODEV;
+}
+
+#endif
Signature · 1 line
2.52.0
#3 lore raw

PATCH v2 2/2 transport: distinguish BAP mic and playback volumes

In reply to Pauli Virtanen

BAP Unicast has two kinds of relevant volumes: playback and microphone. Client Sink and Server Source generally correspond to microphone volume. Broadcast Source and Sink do not have microphone volume. Microphone volumes shall use MICP, not VCP, but currently we confuse them.

Fix by distinguishing the VCP / MICP cases. The shared/micp implementation is incomplete, so leave those volumes unimplemented also in transport.

This fixes setting volume on microphone transport changing the playback volume.

---
 profiles/audio/transport.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
profiles/audio/transport.c +17 -2
index 7fc8d8525..e03f57d4e 100644
@@ -2311,9 +2311,21 @@ static void bap_connecting(struct bt_bap_stream *stream, bool state, int fd,
 	bap_update_links(transport);
 }
 
+static bool transport_bap_is_playback(struct media_transport *transport)
+{
+	struct bap_transport *bap = transport->data;
+	uint8_t dir = bt_bap_stream_get_dir(bap->stream);
+
+	/* Unicast to local/remote Server Sink, or Broadcast */
+	return dir & (BT_BAP_SINK | BT_BAP_BCAST_SINK | BT_BAP_BCAST_SOURCE);
+}
+
 static int transport_bap_get_volume(struct media_transport *transport)
 {
-	return bt_audio_vcp_get_volume(transport->device);
+	if (transport_bap_is_playback(transport))
+		return bt_audio_vcp_get_volume(transport->device);
+	else
+		return -ENOTSUP; /* TODO: MICP */
 }
 
 static int transport_bap_set_volume(struct media_transport *transport,
@@ -2322,7 +2334,10 @@ static int transport_bap_set_volume(struct media_transport *transport,
 	if (volume < 0 || volume > 255)
 		return -EINVAL;
 
-	return bt_audio_vcp_set_volume(transport->device, volume);
+	if (transport_bap_is_playback(transport))
+		return bt_audio_vcp_set_volume(transport->device, volume);
+	else
+		return -ENOTSUP; /* TODO: MICP */
 }
 
 static void transport_bap_destroy(void *data)
Signature · 1 line
2.52.0
#2 lore raw
In reply to Pauli Virtanen

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/project/bluetooth/list/?series=1038698

---Test result---

Test Summary:

CheckPatch                    PENDING   0.31 seconds
GitLint                       PENDING   0.36 seconds
BuildEll                      PASS      20.04 seconds
BluezMake                     PASS      650.83 seconds
MakeCheck                     PASS      22.16 seconds
MakeDistcheck                 PASS      242.80 seconds
CheckValgrind                 PASS      303.58 seconds
CheckSmatch                   PASS      350.55 seconds
bluezmakeextell               PASS      183.02 seconds
IncrementalBuild              PENDING   0.34 seconds
ScanBuild                     PASS      1025.29 seconds

Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:

##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:

##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series Output:

---
Regards,
Linux Bluetooth

#4 lore raw
In reply to Pauli Virtanen
This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:

Hello:

This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <[email protected]>:

Quoted 9 lines · On Mon, 5 Jan 2026 23:07:53 +0200 you wrote:

v2:
- Drop the bt_bap_stream_is_server() function. The direction can be found based on bt_bap_stream_get_dir(), which for BAP Client indicates the remote endpoint, and for BAP Server the local endpoint direction.

Its return value is a bit strange for broadcast, as lpac BCAST_SINK -> dir BCAST_SOURCE.

[...]

Here is the summary with links:
- [BlueZ,v2,1/2] transport: clean up volume set/get for A2DP and VCP

    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=76933585dc48
  - [BlueZ,v2,2/2] transport: distinguish BAP mic and playback volumes
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1287ac9068b7

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html