[PATCH v3 BlueZ 22/27] alert: Add support for ringer setting notification

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Eder Ruiz Maria <eder.ruiz@xxxxxxxxxxxxx>

When the agent reports a ringer setting change, a ringer setting
notification is sent to the peer device (if notification is enabled).
---
 profiles/alert/server.c |  156 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 2 deletions(-)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 95dee04..10c4160 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -31,6 +31,7 @@
 #include <gdbus.h>
 #include <glib.h>
 #include <bluetooth/uuid.h>
+#include <stdlib.h>
 
 #include "dbus-common.h"
 #include "att.h"
@@ -45,6 +46,8 @@
 #include "server.h"
 #include "profile.h"
 #include "error.h"
+#include "textfile.h"
+#include "attio.h"
 
 #define PHONE_ALERT_STATUS_SVC_UUID		0x180E
 #define ALERT_NOTIF_SVC_UUID			0x1811
@@ -89,6 +92,11 @@ enum {
 	RINGER_NORMAL,
 };
 
+enum notify_type {
+	NOTIFY_RINGER_SETTING = 0,
+	NOTIFY_SIZE,
+};
+
 struct alert_data {
 	const char *category;
 	char *srv;
@@ -102,6 +110,21 @@ struct alert_adapter {
 	uint16_t supp_unread_alert_cat_handle;
 	uint16_t new_alert_handle;
 	uint16_t unread_alert_handle;
+	uint16_t hnd_ccc[NOTIFY_SIZE];
+	uint16_t hnd_value[NOTIFY_SIZE];
+};
+
+struct notify_data {
+	struct alert_adapter *al_adapter;
+	enum notify_type type;
+	uint8_t *value;
+	size_t len;
+};
+
+struct notify_callback {
+	struct notify_data *notify_data;
+	struct btd_device *device;
+	guint id;
 };
 
 static GSList *registered_alerts = NULL;
@@ -282,6 +305,125 @@ static void watcher_disconnect(DBusConnection *conn, void *user_data)
 	g_slist_foreach(alert_adapters, update_supported_categories, NULL);
 }
 
+static struct btd_device *get_notifiable_device(struct btd_adapter *adapter,
+						char *key, char *value,
+						uint16_t ccc)
+{
+	struct btd_device *device;
+	char addr[18];
+	uint16_t hnd, val;
+	uint8_t bdaddr_type;
+
+	sscanf(key, "%17s#%hhu#%04hX", addr, &bdaddr_type, &hnd);
+
+	if (hnd != ccc)
+		return NULL;
+
+	val = strtol(value, NULL, 16);
+	if (!(val & 0x0001))
+		return NULL;
+
+	device = adapter_find_device(adapter, addr);
+	if (device == NULL)
+		return NULL;
+
+	return btd_device_ref(device);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct notify_callback *cb = user_data;
+	struct notify_data *nd = cb->notify_data;
+	enum notify_type type = nd->type;
+	struct alert_adapter *al_adapter = nd->al_adapter;
+	uint8_t pdu[ATT_MAX_MTU];
+	size_t len = 0;
+
+	switch (type) {
+	case NOTIFY_RINGER_SETTING:
+		len = enc_notification(al_adapter->hnd_value[type],
+				&ringer_setting, sizeof(ringer_setting),
+				pdu, sizeof(pdu));
+		break;
+	default:
+		DBG("Unknown type, could not send notification");
+		goto end;
+	}
+
+	DBG("Send notification for handle: 0x%04x, ccc: 0x%04x",
+					al_adapter->hnd_value[type],
+					al_adapter->hnd_ccc[type]);
+
+	g_attrib_send(attrib, 0, ATT_OP_HANDLE_NOTIFY, pdu, len,
+							NULL, NULL, NULL);
+
+end:
+	btd_device_remove_attio_callback(cb->device, cb->id);
+	btd_device_unref(cb->device);
+	g_free(cb->notify_data->value);
+	g_free(cb->notify_data);
+	g_free(cb);
+}
+
+static void filter_devices_notify(char *key, char *value, void *user_data)
+{
+	struct notify_data *notify_data = user_data;
+	struct alert_adapter *al_adapter = notify_data->al_adapter;
+	enum notify_type type = notify_data->type;
+	struct btd_device *device;
+	struct notify_callback *cb;
+
+	device = get_notifiable_device(al_adapter->adapter, key, value,
+						al_adapter->hnd_ccc[type]);
+	if (device == NULL)
+		return;
+
+	cb = g_new0(struct notify_callback, 1);
+	cb->notify_data = notify_data;
+	cb->device = device;
+	cb->id = btd_device_add_attio_callback(device,
+						attio_connected_cb, NULL, cb);
+}
+
+static void create_filename(char *filename, struct btd_adapter *adapter)
+{
+	char srcaddr[18];
+	bdaddr_t src;
+
+	adapter_get_address(adapter, &src);
+	ba2str(&src, srcaddr);
+
+	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "ccc");
+}
+
+static void notify_devices(struct alert_adapter *al_adapter,
+			enum notify_type type, uint8_t *value, size_t len)
+{
+	struct notify_data *notify_data;
+	char filename[PATH_MAX + 1];
+
+	notify_data = g_new0(struct notify_data, 1);
+	notify_data->al_adapter = al_adapter;
+	notify_data->type = type;
+	notify_data->value = g_memdup(value, len);
+	notify_data->len = len;
+
+	create_filename(filename, al_adapter->adapter);
+	textfile_foreach(filename, filter_devices_notify, notify_data);
+}
+
+static void pasp_notification(enum notify_type type)
+{
+	GSList *it;
+	struct alert_adapter *al_adapter;
+
+	for (it = alert_adapters; it; it = g_slist_next(it)) {
+		al_adapter = it->data;
+
+		notify_devices(al_adapter, type, NULL, 0);
+	}
+}
+
 static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
@@ -344,10 +486,15 @@ static void update_phone_alerts(const char *category, const char *description)
 	unsigned int i;
 
 	if (g_str_equal(category, "ringer")) {
-		if (g_str_equal(description, "enabled"))
+		if (g_str_equal(description, "enabled")) {
 			ringer_setting = RINGER_NORMAL;
-		else if (g_str_equal(description, "disabled"))
+			pasp_notification(NOTIFY_RINGER_SETTING);
+			return;
+		} else if (g_str_equal(description, "disabled")) {
 			ringer_setting = RINGER_SILENT;
+			pasp_notification(NOTIFY_RINGER_SETTING);
+			return;
+		}
 	}
 
 	for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++) {
@@ -619,6 +766,10 @@ static void register_phone_alert_service(struct alert_adapter *al_adapter)
 							ATT_CHAR_PROPER_NOTIFY,
 			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
 			ringer_setting_read, al_adapter->adapter,
+			GATT_OPT_CCC_GET_HANDLE,
+			&al_adapter->hnd_ccc[NOTIFY_RINGER_SETTING],
+			GATT_OPT_CHR_VALUE_GET_HANDLE,
+			&al_adapter->hnd_value[NOTIFY_RINGER_SETTING],
 			GATT_OPT_INVALID);
 }
 
@@ -753,6 +904,7 @@ static void alert_server_remove(struct btd_profile *p,
 
 	alert_adapters = g_slist_remove(alert_adapters, al_adapter);
 	btd_adapter_unref(al_adapter->adapter);
+
 	g_free(al_adapter);
 }
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux