mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	bluez5: backend-native: Add battery level indicator support
This connect to the UPower service and update the +CIND battchg indicator
This commit is contained in:
		
							parent
							
								
									a37aeac273
								
							
						
					
					
						commit
						47700a2214
					
				
					 4 changed files with 371 additions and 4 deletions
				
			
		| 
						 | 
					@ -52,6 +52,7 @@
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "modemmanager.h"
 | 
					#include "modemmanager.h"
 | 
				
			||||||
 | 
					#include "upower.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.native");
 | 
					static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.native");
 | 
				
			||||||
#undef SPA_LOG_TOPIC_DEFAULT
 | 
					#undef SPA_LOG_TOPIC_DEFAULT
 | 
				
			||||||
| 
						 | 
					@ -71,7 +72,7 @@ enum {
 | 
				
			||||||
	HFP_AG_INITIAL_CODEC_SETUP_WAIT
 | 
						HFP_AG_INITIAL_CODEC_SETUP_WAIT
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CIND_INDICATORS "(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5)),(\"roam\",(0-1))"
 | 
					#define CIND_INDICATORS "(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5)),(\"roam\",(0-1)),\"battchg\",(0-5))"
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	CIND_SERVICE = 1,
 | 
						CIND_SERVICE = 1,
 | 
				
			||||||
	CIND_CALL,
 | 
						CIND_CALL,
 | 
				
			||||||
| 
						 | 
					@ -79,6 +80,7 @@ enum {
 | 
				
			||||||
	CIND_CALLHELD,
 | 
						CIND_CALLHELD,
 | 
				
			||||||
	CIND_SIGNAL,
 | 
						CIND_SIGNAL,
 | 
				
			||||||
	CIND_ROAM,
 | 
						CIND_ROAM,
 | 
				
			||||||
 | 
						CIND_BATTERY_LEVEL,
 | 
				
			||||||
	CIND_MAX
 | 
						CIND_MAX
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,9 +117,11 @@ struct impl {
 | 
				
			||||||
	unsigned int defer_setup_enabled:1;
 | 
						unsigned int defer_setup_enabled:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct modem modem;
 | 
						struct modem modem;
 | 
				
			||||||
 | 
						unsigned int battery_level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void *modemmanager;
 | 
						void *modemmanager;
 | 
				
			||||||
	struct spa_source *ring_timer;
 | 
						struct spa_source *ring_timer;
 | 
				
			||||||
 | 
						void *upower;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct transport_data {
 | 
					struct transport_data {
 | 
				
			||||||
| 
						 | 
					@ -835,9 +839,9 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "+CIND:%s", CIND_INDICATORS);
 | 
							rfcomm_send_reply(rfcomm, "+CIND:%s", CIND_INDICATORS);
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "OK");
 | 
							rfcomm_send_reply(rfcomm, "OK");
 | 
				
			||||||
	} else if (spa_strstartswith(buf, "AT+CIND?")) {
 | 
						} else if (spa_strstartswith(buf, "AT+CIND?")) {
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "+CIND: %d,%d,%d,0,%d,%d", backend->modem.network_has_service,
 | 
							rfcomm_send_reply(rfcomm, "+CIND: %d,%d,%d,0,%d,%d,%d", backend->modem.network_has_service,
 | 
				
			||||||
		                  backend->modem.active_call, backend->modem.call_setup, backend->modem.signal_strength,
 | 
							                  backend->modem.active_call, backend->modem.call_setup, backend->modem.signal_strength,
 | 
				
			||||||
		                  backend->modem.network_is_roaming);
 | 
							                  backend->modem.network_is_roaming, backend->battery_level);
 | 
				
			||||||
		rfcomm_send_reply(rfcomm, "OK");
 | 
							rfcomm_send_reply(rfcomm, "OK");
 | 
				
			||||||
	} else if (spa_strstartswith(buf, "AT+CMER")) {
 | 
						} else if (spa_strstartswith(buf, "AT+CMER")) {
 | 
				
			||||||
		int mode, keyp, disp, ind;
 | 
							int mode, keyp, disp, ind;
 | 
				
			||||||
| 
						 | 
					@ -2530,6 +2534,16 @@ static void set_call_setup(enum call_setup value, void *user_data)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void set_battery_level(unsigned int level, void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *backend = user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (backend->battery_level != level) {
 | 
				
			||||||
 | 
							backend->battery_level = level;
 | 
				
			||||||
 | 
							send_ciev_for_each_rfcomm(backend, CIND_BATTERY_LEVEL, level);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void set_modem_operator_name(const char *name, void *user_data)
 | 
					static void set_modem_operator_name(const char *name, void *user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *backend = user_data;
 | 
						struct impl *backend = user_data;
 | 
				
			||||||
| 
						 | 
					@ -2611,6 +2625,11 @@ static int backend_native_free(void *data)
 | 
				
			||||||
		backend->modemmanager = NULL;
 | 
							backend->modemmanager = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (backend->upower) {
 | 
				
			||||||
 | 
							upower_unregister(backend->upower);
 | 
				
			||||||
 | 
							backend->upower = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (backend->ring_timer)
 | 
						if (backend->ring_timer)
 | 
				
			||||||
		spa_loop_utils_destroy_source(backend->loop_utils, backend->ring_timer);
 | 
							spa_loop_utils_destroy_source(backend->loop_utils, backend->ring_timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2740,6 +2759,7 @@ struct spa_bt_backend *backend_native_new(struct spa_bt_monitor *monitor,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	backend->modemmanager = mm_register(backend->log, backend->conn, &mm_ops, backend);
 | 
						backend->modemmanager = mm_register(backend->log, backend->conn, &mm_ops, backend);
 | 
				
			||||||
 | 
						backend->upower = upower_register(backend->log, backend->conn, set_battery_level, backend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &backend->this;
 | 
						return &backend->this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,7 @@ if get_option('bluez5-backend-hsp-native').allowed() or get_option('bluez5-backe
 | 
				
			||||||
    bluez5_deps += mm_dep
 | 
					    bluez5_deps += mm_dep
 | 
				
			||||||
    bluez5_sources += ['modemmanager.c']
 | 
					    bluez5_sources += ['modemmanager.c']
 | 
				
			||||||
  endif
 | 
					  endif
 | 
				
			||||||
  bluez5_sources += ['backend-native.c']
 | 
					  bluez5_sources += ['backend-native.c', 'upower.c']
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if get_option('bluez5-backend-ofono').allowed()
 | 
					if get_option('bluez5-backend-ofono').allowed()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										311
									
								
								spa/plugins/bluez5/upower.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								spa/plugins/bluez5/upower.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,311 @@
 | 
				
			||||||
 | 
					/* Spa Bluez5 UPower proxy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright © 2022 Collabora
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
				
			||||||
 | 
					 * copy of this software and associated documentation files (the "Software"),
 | 
				
			||||||
 | 
					 * to deal in the Software without restriction, including without limitation
 | 
				
			||||||
 | 
					 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
				
			||||||
 | 
					 * and/or sell copies of the Software, and to permit persons to whom the
 | 
				
			||||||
 | 
					 * Software is furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The above copyright notice and this permission notice (including the next
 | 
				
			||||||
 | 
					 * paragraph) shall be included in all copies or substantial portions of the
 | 
				
			||||||
 | 
					 * Software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
				
			||||||
 | 
					 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
				
			||||||
 | 
					 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
				
			||||||
 | 
					 * DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <spa/utils/string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "upower.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define UPOWER_SERVICE "org.freedesktop.UPower"
 | 
				
			||||||
 | 
					#define UPOWER_DEVICE_INTERFACE UPOWER_SERVICE ".Device"
 | 
				
			||||||
 | 
					#define UPOWER_DISPLAY_DEVICE_OBJECT "/org/freedesktop/UPower/devices/DisplayDevice"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct impl {
 | 
				
			||||||
 | 
						struct spa_bt_monitor *monitor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct spa_log *log;
 | 
				
			||||||
 | 
						DBusConnection *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool filters_added;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *user_data;
 | 
				
			||||||
 | 
						void (*set_battery_level)(unsigned int level, void *user_data);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DBusHandlerResult upower_parse_percentage(struct impl *this, DBusMessageIter *variant_i)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						double percentage;
 | 
				
			||||||
 | 
						unsigned int battery_level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbus_message_iter_get_basic(variant_i, &percentage);
 | 
				
			||||||
 | 
						spa_log_debug(this->log, "Battery level: %f %%", percentage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						battery_level = (unsigned int) round(percentage / 20.0);
 | 
				
			||||||
 | 
						this->set_battery_level(battery_level, this->user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return DBUS_HANDLER_RESULT_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void upower_get_percentage_properties_reply(DBusPendingCall *pending, void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *backend = user_data;
 | 
				
			||||||
 | 
						DBusMessage *r;
 | 
				
			||||||
 | 
						DBusMessageIter i, variant_i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r = dbus_pending_call_steal_reply(pending);
 | 
				
			||||||
 | 
						if (r == NULL)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
 | 
				
			||||||
 | 
							spa_log_error(backend->log, "Failed to get percentage from UPower: %s",
 | 
				
			||||||
 | 
									dbus_message_get_error_name(r));
 | 
				
			||||||
 | 
							goto finish;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dbus_message_iter_init(r, &i) || !spa_streq(dbus_message_get_signature(r), "v")) {
 | 
				
			||||||
 | 
							spa_log_error(backend->log, "Invalid arguments in Get() reply");
 | 
				
			||||||
 | 
							goto finish;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbus_message_iter_recurse(&i, &variant_i);
 | 
				
			||||||
 | 
						upower_parse_percentage(backend, &variant_i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					finish:
 | 
				
			||||||
 | 
						dbus_message_unref(r);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void upower_clean(struct impl *this)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						this->set_battery_level(0, this->user_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DBusHandlerResult upower_filter_cb(DBusConnection *bus, DBusMessage *m, void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *this = user_data;
 | 
				
			||||||
 | 
						DBusError err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbus_error_init(&err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
 | 
				
			||||||
 | 
							const char *name, *old_owner, *new_owner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							spa_log_debug(this->log, "Name owner changed %s", dbus_message_get_path(m));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!dbus_message_get_args(m, &err,
 | 
				
			||||||
 | 
										   DBUS_TYPE_STRING, &name,
 | 
				
			||||||
 | 
										   DBUS_TYPE_STRING, &old_owner,
 | 
				
			||||||
 | 
										   DBUS_TYPE_STRING, &new_owner,
 | 
				
			||||||
 | 
										   DBUS_TYPE_INVALID)) {
 | 
				
			||||||
 | 
								spa_log_error(this->log, "Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err.message);
 | 
				
			||||||
 | 
								goto finish;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (spa_streq(name, UPOWER_SERVICE)) {
 | 
				
			||||||
 | 
								if (old_owner && *old_owner) {
 | 
				
			||||||
 | 
									spa_log_debug(this->log, "UPower daemon disappeared (%s)", old_owner);
 | 
				
			||||||
 | 
									upower_clean(this);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (new_owner && *new_owner) {
 | 
				
			||||||
 | 
									DBusPendingCall *call;
 | 
				
			||||||
 | 
									static const char* upower_device_interface = UPOWER_DEVICE_INTERFACE;
 | 
				
			||||||
 | 
									static const char* percentage_property = "Percentage";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									spa_log_debug(this->log, "UPower daemon appeared (%s)", new_owner);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									m = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get");
 | 
				
			||||||
 | 
									if (m == NULL)
 | 
				
			||||||
 | 
										goto finish;
 | 
				
			||||||
 | 
									dbus_message_append_args(m, DBUS_TYPE_STRING, &upower_device_interface,
 | 
				
			||||||
 | 
											         DBUS_TYPE_STRING, &percentage_property, DBUS_TYPE_INVALID);
 | 
				
			||||||
 | 
									dbus_connection_send_with_reply(this->conn, m, &call, -1);
 | 
				
			||||||
 | 
									dbus_pending_call_set_notify(call, upower_get_percentage_properties_reply, this, NULL);
 | 
				
			||||||
 | 
									dbus_message_unref(m);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (dbus_message_is_signal(m, DBUS_INTERFACE_PROPERTIES, DBUS_SIGNAL_PROPERTIES_CHANGED)) {
 | 
				
			||||||
 | 
							const char *path;
 | 
				
			||||||
 | 
							DBusMessageIter iface_i, props_i;
 | 
				
			||||||
 | 
							const char *interface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!dbus_message_iter_init(m, &iface_i) || !spa_streq(dbus_message_get_signature(m), "sa{sv}as")) {
 | 
				
			||||||
 | 
									spa_log_error(this->log, "Invalid signature found in PropertiesChanged");
 | 
				
			||||||
 | 
									goto finish;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dbus_message_iter_get_basic(&iface_i, &interface);
 | 
				
			||||||
 | 
							dbus_message_iter_next(&iface_i);
 | 
				
			||||||
 | 
							spa_assert(dbus_message_iter_get_arg_type(&iface_i) == DBUS_TYPE_ARRAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dbus_message_iter_recurse(&iface_i, &props_i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							path = dbus_message_get_path(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (spa_streq(interface, UPOWER_DEVICE_INTERFACE)) {
 | 
				
			||||||
 | 
								spa_log_debug(this->log, "Properties changed on %s", path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								while (dbus_message_iter_get_arg_type(&props_i) != DBUS_TYPE_INVALID) {
 | 
				
			||||||
 | 
									DBusMessageIter i, value_i;
 | 
				
			||||||
 | 
									const char *key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									dbus_message_iter_recurse(&props_i, &i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									dbus_message_iter_get_basic(&i, &key);
 | 
				
			||||||
 | 
									dbus_message_iter_next(&i);
 | 
				
			||||||
 | 
									dbus_message_iter_recurse(&i, &value_i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(spa_streq(key, "Percentage"))
 | 
				
			||||||
 | 
										upower_parse_percentage(this, &value_i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									dbus_message_iter_next(&props_i);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					finish:
 | 
				
			||||||
 | 
						return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int add_filters(struct impl *this)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						DBusError err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->filters_added)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbus_error_init(&err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dbus_connection_add_filter(this->conn, upower_filter_cb, this, NULL)) {
 | 
				
			||||||
 | 
							spa_log_error(this->log, "failed to add filter function");
 | 
				
			||||||
 | 
							goto fail;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbus_bus_add_match(this->conn,
 | 
				
			||||||
 | 
								"type='signal',sender='org.freedesktop.DBus',"
 | 
				
			||||||
 | 
								"interface='org.freedesktop.DBus',member='NameOwnerChanged'," "arg0='" UPOWER_SERVICE "'", &err);
 | 
				
			||||||
 | 
						dbus_bus_add_match(this->conn,
 | 
				
			||||||
 | 
								"type='signal',sender='" UPOWER_SERVICE "',"
 | 
				
			||||||
 | 
								"interface='" DBUS_INTERFACE_PROPERTIES "',member='" DBUS_SIGNAL_PROPERTIES_CHANGED "',"
 | 
				
			||||||
 | 
								"path='" UPOWER_DISPLAY_DEVICE_OBJECT "',arg0='" UPOWER_DEVICE_INTERFACE "'", &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->filters_added = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fail:
 | 
				
			||||||
 | 
						dbus_error_free(&err);
 | 
				
			||||||
 | 
						return -EIO;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool is_dbus_service_available(struct impl *this, const char *service)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						DBusMessage *m, *r;
 | 
				
			||||||
 | 
						DBusError err;
 | 
				
			||||||
 | 
						bool success = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m = dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus",
 | 
				
			||||||
 | 
						                                  "org.freedesktop.DBus", "NameHasOwner");
 | 
				
			||||||
 | 
						if (m == NULL)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						dbus_message_append_args(m, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbus_error_init(&err);
 | 
				
			||||||
 | 
						r = dbus_connection_send_with_reply_and_block(this->conn, m, -1, &err);
 | 
				
			||||||
 | 
						dbus_message_unref(m);
 | 
				
			||||||
 | 
						m = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (r == NULL) {
 | 
				
			||||||
 | 
							spa_log_info(this->log, "NameHasOwner failed for %s", service);
 | 
				
			||||||
 | 
							dbus_error_free(&err);
 | 
				
			||||||
 | 
							goto finish;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
 | 
				
			||||||
 | 
							spa_log_error(this->log, "NameHasOwner() returned error: %s", dbus_message_get_error_name(r));
 | 
				
			||||||
 | 
							goto finish;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dbus_message_get_args(r, &err,
 | 
				
			||||||
 | 
									   DBUS_TYPE_BOOLEAN, &success,
 | 
				
			||||||
 | 
									   DBUS_TYPE_INVALID)) {
 | 
				
			||||||
 | 
							spa_log_error(this->log, "Failed to parse NameHasOwner() reply: %s", err.message);
 | 
				
			||||||
 | 
							dbus_error_free(&err);
 | 
				
			||||||
 | 
							goto finish;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					finish:
 | 
				
			||||||
 | 
						if (r)
 | 
				
			||||||
 | 
							dbus_message_unref(r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return success;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *upower_register(struct spa_log *log,
 | 
				
			||||||
 | 
					                      void *dbus_connection,
 | 
				
			||||||
 | 
					                      void (*set_battery_level)(unsigned int level, void *user_data),
 | 
				
			||||||
 | 
					                      void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_assert(log);
 | 
				
			||||||
 | 
						spa_assert(dbus_connection);
 | 
				
			||||||
 | 
						spa_assert(set_battery_level);
 | 
				
			||||||
 | 
						spa_assert(user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this = calloc(1, sizeof(struct impl));
 | 
				
			||||||
 | 
						if (this == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->log = log;
 | 
				
			||||||
 | 
						this->conn = dbus_connection;
 | 
				
			||||||
 | 
						this->set_battery_level = set_battery_level;
 | 
				
			||||||
 | 
					    this->user_data = user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (add_filters(this) < 0) {
 | 
				
			||||||
 | 
							goto fail4;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_dbus_service_available(this, UPOWER_SERVICE)) {
 | 
				
			||||||
 | 
							DBusMessage *m;
 | 
				
			||||||
 | 
							DBusPendingCall *call;
 | 
				
			||||||
 | 
							static const char* upower_device_interface = UPOWER_DEVICE_INTERFACE;
 | 
				
			||||||
 | 
							static const char* percentage_property = "Percentage";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get");
 | 
				
			||||||
 | 
							if (m == NULL)
 | 
				
			||||||
 | 
								goto fail4;
 | 
				
			||||||
 | 
							dbus_message_append_args(m, DBUS_TYPE_STRING, &upower_device_interface,
 | 
				
			||||||
 | 
							                         DBUS_TYPE_STRING, &percentage_property, DBUS_TYPE_INVALID);
 | 
				
			||||||
 | 
							dbus_connection_send_with_reply(this->conn, m, &call, -1);
 | 
				
			||||||
 | 
							dbus_pending_call_set_notify(call, upower_get_percentage_properties_reply, this, NULL);
 | 
				
			||||||
 | 
							dbus_message_unref(m);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fail4:
 | 
				
			||||||
 | 
					    free(this);
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void upower_unregister(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *this = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->filters_added) {
 | 
				
			||||||
 | 
							dbus_connection_remove_filter(this->conn, upower_filter_cb, this);
 | 
				
			||||||
 | 
							this->filters_added = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						free(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								spa/plugins/bluez5/upower.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								spa/plugins/bluez5/upower.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					/* Spa Bluez5 UPower proxy
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright © 2022 Collabora
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
				
			||||||
 | 
					 * copy of this software and associated documentation files (the "Software"),
 | 
				
			||||||
 | 
					 * to deal in the Software without restriction, including without limitation
 | 
				
			||||||
 | 
					 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
				
			||||||
 | 
					 * and/or sell copies of the Software, and to permit persons to whom the
 | 
				
			||||||
 | 
					 * Software is furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The above copyright notice and this permission notice (including the next
 | 
				
			||||||
 | 
					 * paragraph) shall be included in all copies or substantial portions of the
 | 
				
			||||||
 | 
					 * Software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
				
			||||||
 | 
					 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
				
			||||||
 | 
					 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
				
			||||||
 | 
					 * DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SPA_BLUEZ5_UPOWER_H_
 | 
				
			||||||
 | 
					#define SPA_BLUEZ5_UPOWER_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "defs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *upower_register(struct spa_log *log,
 | 
				
			||||||
 | 
					                      void *dbus_connection,
 | 
				
			||||||
 | 
					                      void (*set_battery_level)(unsigned int level, void *user_data),
 | 
				
			||||||
 | 
					                      void *user_data);
 | 
				
			||||||
 | 
					void upower_unregister(void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue