diff mbox series

[BlueZ,2/2] profiles/audio: asha: Only expose device after we have attributes

Message ID 20250422054547.132400-3-sanchayan@asymptotic.io
State New
Headers show
Series Fixes for re-connection issues with ASHA profile | expand

Commit Message

Sanchayan Maity April 22, 2025, 5:45 a.m. UTC
From: Arun Raghavan <arun@asymptotic.io>

Let's get the PSM and read-only properties before we expose the device
and transport.
---
 profiles/audio/asha.c |  6 +++---
 src/shared/asha.c     | 30 +++++++++++++++++++++++++++++-
 src/shared/asha.h     |  7 ++++++-
 3 files changed, 38 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/profiles/audio/asha.c b/profiles/audio/asha.c
index df283dd22..39c165855 100644
--- a/profiles/audio/asha.c
+++ b/profiles/audio/asha.c
@@ -451,24 +451,24 @@  static int asha_source_accept(struct btd_service *service)
 
 	ba2str(device_get_address(device), addr);
 	DBG("Accepting ASHA connection on %s", addr);
 
 	if (!asha_dev) {
 		/* Can this actually happen? */
 		DBG("Not handling ASHA profile");
 		return -1;
 	}
 
-	if (!bt_asha_probe(asha_dev->asha, db, client))
+	if (!bt_asha_probe(asha_dev->asha, db, client,
+		(bt_asha_probe_cb_t) asha_source_endpoint_register, asha_dev)) {
 		return -1;
-
-	asha_source_endpoint_register(asha_dev);
+	}
 
 	btd_service_connecting_complete(service, 0);
 
 	return 0;
 }
 
 static int asha_source_disconnect(struct btd_service *service)
 {
 	struct btd_device *device = btd_service_get_device(service);
 	struct bt_asha_device *asha_dev = btd_service_get_user_data(service);
diff --git a/src/shared/asha.c b/src/shared/asha.c
index e7bba4cc4..4033a4386 100644
--- a/src/shared/asha.c
+++ b/src/shared/asha.c
@@ -168,20 +168,24 @@  void bt_asha_reset(struct bt_asha *asha)
 						asha->status_notify_id);
 	}
 
 	gatt_db_unref(asha->db);
 	asha->db = NULL;
 
 	bt_gatt_client_unref(asha->client);
 	asha->client = NULL;
 
 	asha->psm = 0;
+	memset(asha->hisyncid, 0, sizeof(asha->hisyncid));
+
+	asha->probe_cb = NULL;
+	asha->probe_cb_data = NULL;
 
 	update_asha_set(asha, false);
 }
 
 void bt_asha_state_reset(struct bt_asha *asha)
 {
 	asha->state = ASHA_STOPPED;
 
 	asha->cb = NULL;
 	asha->cb_user_data = NULL;
@@ -326,41 +330,59 @@  bool bt_asha_set_volume(struct bt_asha *asha, int8_t volume)
 
 static bool uuid_cmp(const char *uuid1, const bt_uuid_t *uuid2)
 {
 	bt_uuid_t lhs;
 
 	bt_string_to_uuid(&lhs, uuid1);
 
 	return bt_uuid_cmp(&lhs, uuid2) == 0;
 }
 
+static void check_probe_done(struct bt_asha *asha)
+{
+	uint8_t zeroes[8] = { 0, };
+
+	/* Once we have ROPs & PSM, we should be good to go */
+	if (asha->psm == 0 ||
+		memcmp(asha->hisyncid, zeroes, sizeof(zeroes) == 0))
+		return;
+
+	if (asha->probe_cb) {
+		asha->probe_cb(asha->probe_cb_data);
+		asha->probe_cb = NULL;
+		asha->probe_cb_data = NULL;
+	}
+}
+
 static void read_psm(bool success,
 			uint8_t att_ecode,
 			const uint8_t *value,
 			uint16_t length,
 			void *user_data)
 {
 	struct bt_asha *asha = user_data;
 
 	if (!success) {
 		DBG("Reading PSM failed with ATT error: %u", att_ecode);
 		return;
 	}
 
 	if (length != 2) {
 		DBG("Reading PSM failed: unexpected length %u", length);
 		return;
 	}
 
 	asha->psm = get_le16(value);
 
 	DBG("Got PSM: %u", asha->psm);
+
+	check_probe_done(asha);
 }
 
 static void read_rops(bool success,
 			uint8_t att_ecode,
 			const uint8_t *value,
 			uint16_t length,
 			void *user_data)
 {
 	struct bt_asha *asha = user_data;
 
@@ -391,20 +413,22 @@  static void read_rops(bool success,
 	asha->render_delay = get_le16(&value[11]);
 	/* byte 13 & 14 are reserved */
 	/* Codec IDs */
 	asha->codec_ids = get_le16(&value[15]);
 
 	DBG("Got ROPS: side %u, binaural %u, csis: %u, delay %u, codecs: %u",
 			asha->right_side, asha->binaural, asha->csis_supported,
 			asha->render_delay, asha->codec_ids);
 
 	update_asha_set(asha, true);
+
+	check_probe_done(asha);
 }
 
 static void audio_status_register(uint16_t att_ecode, void *user_data)
 {
 	if (att_ecode)
 		DBG("AudioStatusPoint register failed 0x%04x", att_ecode);
 	else
 		DBG("AudioStatusPoint register succeeded");
 }
 
@@ -493,27 +517,31 @@  static void foreach_asha_service(struct gatt_db_attribute *attr,
 	struct bt_asha *asha = user_data;
 
 	DBG("Found ASHA GATT service");
 
 	asha->attr = attr;
 	gatt_db_service_set_claimed(attr, true);
 	gatt_db_service_foreach_char(asha->attr, handle_characteristic, asha);
 }
 
 bool bt_asha_probe(struct bt_asha *asha, struct gatt_db *db,
-						struct bt_gatt_client *client)
+		struct bt_gatt_client *client, bt_asha_probe_cb_t probe_cb,
+							void *cb_user_data)
 {
 	bt_uuid_t asha_uuid;
 
 	asha->db = gatt_db_ref(db);
 	asha->client = bt_gatt_client_clone(client);
 
+	asha->probe_cb = probe_cb;
+	asha->probe_cb_data = cb_user_data;
+
 	bt_uuid16_create(&asha_uuid, ASHA_SERVICE);
 	gatt_db_foreach_service(db, &asha_uuid, foreach_asha_service, asha);
 
 	if (!asha->attr) {
 		error("ASHA attribute not found");
 		bt_asha_reset(asha);
 		return false;
 	}
 
 	if (!asha_devices)
diff --git a/src/shared/asha.h b/src/shared/asha.h
index e87a9fc3f..821c2a625 100644
--- a/src/shared/asha.h
+++ b/src/shared/asha.h
@@ -16,54 +16,59 @@ 
 #include <stdint.h>
 
 enum bt_asha_state_t {
 	ASHA_STOPPED = 0,
 	ASHA_STARTING,
 	ASHA_STARTED,
 	ASHA_STOPPING,
 };
 
 typedef void (*bt_asha_cb_t)(int status, void *data);
+typedef void (*bt_asha_probe_cb_t)(void *data);
 
 struct bt_asha {
 	struct bt_gatt_client *client;
 	struct gatt_db *db;
 	struct gatt_db_attribute *attr;
 	uint16_t acp_handle;
 	uint16_t volume_handle;
 	unsigned int status_notify_id;
 
 	uint16_t psm;
 	bool right_side;
 	bool binaural;
 	bool csis_supported;
 	bool coc_streaming_supported;
 	uint8_t hisyncid[8];
 	uint16_t render_delay;
 	uint16_t codec_ids;
 	int8_t volume;
 
 	enum bt_asha_state_t state;
 	bt_asha_cb_t cb;
 	void *cb_user_data;
+
+	bt_asha_probe_cb_t probe_cb;
+	void *probe_cb_data;
 };
 
 struct bt_asha_set {
 	uint8_t hisyncid[8];
 	struct bt_asha *left;
 	struct bt_asha *right;
 };
 
 struct bt_asha *bt_asha_new(void);
 void bt_asha_reset(struct bt_asha *asha);
 void bt_asha_state_reset(struct bt_asha *asha);
 void bt_asha_free(struct bt_asha *asha);
 
 unsigned int bt_asha_start(struct bt_asha *asha, bt_asha_cb_t cb,
 							void *user_data);
 unsigned int bt_asha_stop(struct bt_asha *asha, bt_asha_cb_t cb,
 							void *user_data);
 
 bool bt_asha_set_volume(struct bt_asha *asha, int8_t volume);
 
 bool bt_asha_probe(struct bt_asha *asha, struct gatt_db *db,
-						struct bt_gatt_client *client);
+		struct bt_gatt_client *client, bt_asha_probe_cb_t probe_cb,
+							void *cb_user_data);