Linux-Bluetooth Archive mirror
 help / color / mirror / Atom feed
From: Arun Raghavan <arun@asymptotic.io>
To: linux-bluetooth@vger.kernel.org
Cc: Arun Raghavan <arun@asymptotic.io>
Subject: [PATCH BlueZ 2/5] asha: Implement volume on transport
Date: Wed,  8 May 2024 11:46:01 -0400	[thread overview]
Message-ID: <20240508154604.276763-3-arun@asymptotic.io> (raw)
In-Reply-To: <20240508154604.276763-1-arun@asymptotic.io>

We convert from the spec definition of the range to the DBus API range
to make it easier for clients to not have to worry about that detail,
and share an implementation with other uses of MediaTransport1.
---
 profiles/audio/asha.c      | 88 +++++++++++++++++++++++++++++++++++---
 profiles/audio/asha.h      |  4 ++
 profiles/audio/transport.c | 28 +++++++++++-
 3 files changed, 112 insertions(+), 8 deletions(-)

diff --git a/profiles/audio/asha.c b/profiles/audio/asha.c
index c6769038f..a372e0db3 100644
--- a/profiles/audio/asha.c
+++ b/profiles/audio/asha.c
@@ -65,7 +65,9 @@ struct asha_device {
 	struct gatt_db *db;
 	struct gatt_db_attribute *attr;
 	uint16_t acp_handle;
-	unsigned int notify_id;
+	uint16_t volume_handle;
+	unsigned int status_notify_id;
+	unsigned int volume_notify_id;
 
 	uint16_t psm;
 	bool right_side;
@@ -75,6 +77,7 @@ struct asha_device {
 	uint8_t hisyncid[8];
 	uint16_t render_delay;
 	uint16_t codec_ids;
+	int8_t volume;
 
 	struct media_transport *transport;
 	int fd;
@@ -95,9 +98,15 @@ static struct asha_device *asha_device_new(void)
 
 static void asha_device_reset(struct asha_device *asha)
 {
-	if (asha->notify_id)
+	if (asha->status_notify_id) {
 		bt_gatt_client_unregister_notify(asha->client,
-				asha->notify_id);
+						asha->status_notify_id);
+	}
+
+	if (asha->volume_notify_id) {
+		bt_gatt_client_unregister_notify(asha->client,
+						asha->volume_notify_id);
+	}
 
 	gatt_db_unref(asha->db);
 	asha->db = NULL;
@@ -244,6 +253,7 @@ unsigned int asha_device_start(struct asha_device *asha, asha_cb_t cb,
 		0x01, // START
 		0x01, // G.722, 16 kHz
 		0,   // Unknown media type
+		asha->volume, // Volume
 		0,   // Other disconnected
 	};
 	int ret;
@@ -290,6 +300,24 @@ unsigned int asha_device_stop(struct asha_device *asha, asha_cb_t cb,
 	return asha->resume_id;
 }
 
+int8_t asha_device_get_volume(struct asha_device *asha)
+{
+	return asha->volume;
+}
+
+bool asha_device_set_volume(struct asha_device *asha, int8_t volume)
+{
+	if (!bt_gatt_client_write_value(asha->client, asha->volume_handle,
+				(const uint8_t *)&volume, 1, NULL, NULL,
+				NULL)) {
+		error("Error writing ACP start");
+		return false;
+	}
+
+	asha->volume = volume;
+	return true;
+}
+
 static char *make_endpoint_path(struct asha_device *asha)
 {
 	char *path;
@@ -410,6 +438,39 @@ void audio_status_notify(uint16_t value_handle, const uint8_t *value,
 	}
 }
 
+static void read_volume(bool success,
+			uint8_t att_ecode,
+			const uint8_t *value,
+			uint16_t length,
+			void *user_data)
+{
+	struct asha_device *asha = user_data;
+
+	if (!success) {
+		DBG("Reading volume failed with ATT errror: %u", att_ecode);
+		return;
+	}
+
+	if (length != 2) {
+		DBG("Reading volume failed: unexpected length %u", length);
+		return;
+	}
+
+	asha->volume = get_s8(value);
+
+	DBG("Got volume: %d", asha->volume);
+}
+
+void volume_notify(uint16_t value_handle, const uint8_t *value,
+					uint16_t length, void *user_data)
+{
+	struct asha_device *asha = user_data;
+
+	asha->volume = get_s8(value);
+
+	DBG("Volume changed: %d", asha->volume);
+}
+
 static void handle_characteristic(struct gatt_db_attribute *attr,
 								void *user_data)
 {
@@ -430,16 +491,29 @@ static void handle_characteristic(struct gatt_db_attribute *attr,
 	} if (uuid_cmp(ASHA_CHRC_READ_ONLY_PROPERTIES_UUID, &uuid)) {
 		if (!bt_gatt_client_read_value(asha->client, value_handle,
 					read_rops, asha, NULL))
-			DBG("Failed to send request to read battery level");
+			DBG("Failed to send request for readonly properties");
 	} if (uuid_cmp(ASHA_CHRC_AUDIO_CONTROL_POINT_UUID, &uuid)) {
 		// Store this for later writes
 		asha->acp_handle = value_handle;
+	} if (uuid_cmp(ASHA_CHRC_VOLUME_UUID, &uuid)) {
+		// Store this for later reads and writes
+		asha->volume_handle = value_handle;
+		asha->volume_notify_id =
+			bt_gatt_client_register_notify(asha->client,
+				value_handle, NULL, volume_notify, asha,
+				NULL);
+		if (!asha->status_notify_id)
+			DBG("Failed to send request to notify volume");
+		if (!bt_gatt_client_read_value(asha->client, value_handle,
+					read_volume, asha, NULL))
+			DBG("Failed to send request to volume");
 	} if (uuid_cmp(ASHA_CHRC_AUDIO_STATUS_UUID, &uuid)) {
-		asha->notify_id = bt_gatt_client_register_notify(asha->client,
+		asha->status_notify_id =
+			bt_gatt_client_register_notify(asha->client,
 				value_handle, NULL, audio_status_notify, asha,
 				NULL);
-		if (!asha->notify_id)
-			DBG("Failed to send request to read battery level");
+		if (!asha->status_notify_id)
+			DBG("Failed to send request to notify AudioStatus");
 	} else {
 		char uuid_str[MAX_LEN_UUID_STR];
 
diff --git a/profiles/audio/asha.h b/profiles/audio/asha.h
index 0fc28e8a3..20bcaa65b 100644
--- a/profiles/audio/asha.h
+++ b/profiles/audio/asha.h
@@ -10,6 +10,7 @@
  *
  */
 
+#include <stdbool.h>
 #include <stdint.h>
 
 struct asha_device;
@@ -32,3 +33,6 @@ unsigned int asha_device_start(struct asha_device *asha, asha_cb_t cb,
 		void *user_data);
 unsigned int asha_device_stop(struct asha_device *asha, asha_cb_t cb,
 		void *user_data);
+
+int8_t asha_device_get_volume(struct asha_device *asha);
+bool asha_device_set_volume(struct asha_device *asha, int8_t volume);
diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index a104d27c0..b85d96914 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -1841,6 +1841,32 @@ static guint transport_asha_suspend(struct media_transport *transport,
 	return ret;
 }
 
+static int8_t transport_asha_get_volume(struct media_transport *transport)
+{
+	struct asha_device *asha = transport->data;
+	int8_t volume;
+	int scaled_volume;
+
+	volume = asha_device_get_volume(asha);
+
+	// Convert -128-0 to 0-127
+	scaled_volume = ((((int) volume) + 128) * 127) / 128;
+
+	return scaled_volume;
+}
+
+static int transport_asha_set_volume(struct media_transport *transport,
+					int8_t volume)
+{
+	struct asha_device *asha = transport->data;
+	int scaled_volume;
+
+	// Convert 0-127 to -128-0
+	scaled_volume = ((((int) volume) * 128) / 127) - 128;
+
+	return asha_device_set_volume(asha, scaled_volume) ? 0 : -EIO;
+}
+
 static void *transport_asha_init(struct media_transport *transport, void *data)
 {
 	/* We just store the struct asha_device on the transport */
@@ -1893,7 +1919,7 @@ static void *transport_asha_init(struct media_transport *transport, void *data)
 			transport_asha_init, \
 			transport_asha_resume, transport_asha_suspend, \
 			NULL, NULL, NULL, \
-			NULL, NULL, \
+			transport_asha_get_volume, transport_asha_set_volume, \
 			NULL)
 
 static const struct media_transport_ops transport_ops[] = {
-- 
2.45.0


  parent reply	other threads:[~2024-05-08 15:46 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-08 15:45 [PATCH BlueZ 0/5] ASHA plugin Arun Raghavan
2024-05-08 15:46 ` [PATCH BlueZ 1/5] profiles: Add initial code for an " Arun Raghavan
2024-05-08 16:25   ` Luiz Augusto von Dentz
2024-05-09  2:16     ` Arun Raghavan
2024-05-08 17:36   ` bluez.test.bot
2024-05-08 15:46 ` Arun Raghavan [this message]
2024-05-08 15:46 ` [PATCH BlueZ 3/5] test: Add a script to test ASHA Arun Raghavan
2024-05-08 16:34   ` Luiz Augusto von Dentz
2024-05-09  2:20     ` Arun Raghavan
2024-05-08 15:46 ` [PATCH BlueZ 4/5] gitignore: Add compile_commands.json Arun Raghavan
2024-05-08 15:46 ` [PATCH BlueZ 5/5] gitignore: Add __pycache__ Arun Raghavan

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=20240508154604.276763-3-arun@asymptotic.io \
    --to=arun@asymptotic.io \
    --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;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).