diff mbox series

[BlueZ,2/5] asha: Implement volume on transport

Message ID 20240508154604.276763-3-arun@asymptotic.io (mailing list archive)
State Superseded
Headers show
Series ASHA plugin | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/CheckPatch fail WARNING:TYPO_SPELLING: 'errror' may be misspelled - perhaps 'error'? #191: FILE: profiles/audio/asha.c:450: + DBG("Reading volume failed with ATT errror: %u", att_ecode); ^^^^^^ ERROR:TRAILING_STATEMENTS: trailing statements should be on next line (or did you mean 'else if'?) #227: FILE: profiles/audio/asha.c:498: + } if (uuid_cmp(ASHA_CHRC_VOLUME_UUID, &uuid)) { /github/workspace/src/src/13658879.patch total: 1 errors, 1 warnings, 190 lines checked NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. /github/workspace/src/src/13658879.patch has style problems, please review. NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS.
tedd_an/GitLint success Gitlint PASS

Commit Message

Arun Raghavan May 8, 2024, 3:46 p.m. UTC
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 mbox series

Patch

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[] = {