1 #include "bluetooth5.h"
2 #include "superptr.hpp"
6 #include <gio/gunixfdlist.h>
9 static const gchar introspection_xml[] =
11 " <interface name='org.bluez.Profile1'>"
12 " <method name='Release'>"
14 " <method name='NewConnection'>"
15 " <arg type='o' name='device' direction='in'/>"
16 " <arg type='h' name='fd' direction='in'/>"
17 " <arg type='a{sv}' name='fd_properties' direction='in'/>"
19 " <method name='RequestDisconnection'>"
20 " <arg type='o' name='device' direction='in'/>"
25 static void handleMethodCall(GDBusConnection *connection,
27 const gchar *object_path,
28 const gchar *interface_name,
29 const gchar *method_name,
31 GDBusMethodInvocation *invocation,
35 Bluetooth5* manager = static_cast<Bluetooth5*>(user_data);
37 std::string method = method_name;
39 if(method == "Release")
43 else if(method == "NewConnection")
45 DebugOut()<<"NewConnection() called"<<endl;
51 DebugOut() << "parameters signature: " << g_variant_get_type_string(parameters) << endl;
53 g_variant_get(parameters,"(oha{sv})", &device, &fd, &iter);
55 DebugOut() << "device: " << device << endl;
57 auto message = g_dbus_method_invocation_get_message(invocation);
59 auto fdList = g_dbus_message_get_unix_fd_list(message);
61 GError* error = nullptr;
63 fd = g_unix_fd_list_get(fdList, 0, &error);
65 auto errorPtr = amb::make_super(error);
69 DebugOut(DebugOut::Error) << "Error trying to get fd: " << errorPtr->message << endl;
76 DebugOut() << "trying to see what properties we got with this call" << endl;
78 while(g_variant_iter_next(iter,"{sv}", &propertyName, &value))
80 auto keyPtr = amb::make_super(propertyName);
81 auto valuePtr = amb::make_super(value);
82 DebugOut() << "key " << keyPtr.get() << "value signature: " << g_variant_get_type_string(valuePtr.get()) << endl;
85 manager->connected_(fd);
87 else if(method == "RequestDisconnection")
89 DebugOut()<<"disconnection."<<endl;
93 g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
97 g_dbus_method_invocation_return_value(invocation, nullptr);
100 static GVariant* getProperty(GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* propertyName, GError** error, gpointer userData)
105 static gboolean setProperty(GDBusConnection * connection, const gchar * sender, const gchar *objectPath,
106 const gchar *interfaceName, const gchar * propertyName, GVariant *value,
107 GError** error, gpointer userData)
112 static const GDBusInterfaceVTable interfaceVTable =
119 std::string findDevice(std::string address, std::string adapterPath)
121 std::string objectPath;
123 GError * proxyError = nullptr;
124 auto managerProxy = amb::make_super(g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
127 "org.freedesktop.DBus.ObjectManager",
128 nullptr, &proxyError));
130 auto proxyErrorPtr = amb::make_super(proxyError);
133 DebugOut(DebugOut::Error)<<"Could not create ObjectManager proxy for Bluez: "<<proxyErrorPtr->message<<endl;
137 GError * getManagerObjectError = nullptr;
139 auto objectMap = amb::make_super(g_dbus_proxy_call_sync(managerProxy.get(), "GetManagedObjects",nullptr, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &getManagerObjectError));
141 auto getManagerObjectErrorPtr = amb::make_super(getManagerObjectError);
143 if(getManagerObjectErrorPtr)
145 DebugOut(DebugOut::Error)<<"Failed call to GetManagedObjects: "<<getManagerObjectErrorPtr->message<<endl;
151 GVariantIter* level2Dict;
153 g_variant_get(objectMap.get(), "(a{oa{sa{sv}}})",&iter);
155 auto iterPtr = amb::make_super(iter);
158 while(g_variant_iter_next(iter, "{oa{sa{sv}}}",&objPath, &level2Dict))
160 auto level2DictPtr = amb::make_super(level2Dict);
161 auto objPathPtr = amb::make_super(objPath);
163 char * interfaceName;
164 GVariantIter* innerDict;
165 while(g_variant_iter_next(level2DictPtr.get(), "{sa{sv}}", &interfaceName, &innerDict))
167 auto interfaceNamePtr = amb::make_super(interfaceName);
168 auto innerDictPtr = amb::make_super(innerDict);
169 if(std::string(interfaceNamePtr.get()) == "org.bluez.Device1")
174 while(objectPath == "" && g_variant_iter_next(innerDictPtr.get(),"{sv}", &propertyName, &value))
176 auto propertyNamePtr = amb::make_super(propertyName);
177 auto valuePtr = amb::make_super(value);
179 if(std::string(propertyNamePtr.get()) == "Address")
182 g_variant_get(valuePtr.get(),"s",&addy);
184 auto addyPtr = amb::make_super(addy);
186 if(addyPtr && std::string(addyPtr.get()) == address)
188 objectPath = objPathPtr.get();
191 ///TODO: filter only devices that have the specified adapter
200 Bluetooth5::Bluetooth5()
202 GError* errorIntrospection = NULL;
204 GDBusNodeInfo* introspection = g_dbus_node_info_new_for_xml(introspection_xml, &errorIntrospection);
206 auto errorIntrospectionPtr = amb::make_super(errorIntrospection);
208 if(errorIntrospectionPtr)
210 DebugOut(DebugOut::Error)<<"in instrospection xml: "<<errorIntrospectionPtr->message<<endl;
214 GError* errorBus = nullptr;
216 GDBusInterfaceInfo* mInterfaceInfo = g_dbus_node_info_lookup_interface(introspection, "org.bluez.Profile1");
218 mConnection = amb::make_super(g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &errorBus));
220 auto errorBusPtr = amb::make_super(errorBus);
224 DebugOut(DebugOut::Error)<<"getting system bus: "<<errorBusPtr->message<<endl;
228 GError* errorRegister = nullptr;
230 int regId = g_dbus_connection_register_object(mConnection.get(), "/org/bluez/spp", mInterfaceInfo, &interfaceVTable, this, NULL, &errorRegister);
232 auto errorRegisterPtr = amb::make_super(errorRegister);
237 DebugOut(DebugOut::Error)<<"Registering org.bluez.Profile1 Interface: "<<errorRegisterPtr->message<<endl;
241 GVariantBuilder builder;
242 g_variant_builder_init(&builder, G_VARIANT_TYPE_DICTIONARY);
244 g_variant_builder_add(&builder, "{sv}", "Name", g_variant_new("s","AMB spp client"));
245 g_variant_builder_add(&builder, "{sv}", "Role", g_variant_new("s","client"));
246 g_variant_builder_add(&builder, "{sv}", "AutoConnect", g_variant_new("b",true));
248 GError* errorRegisterCall = nullptr;
250 g_dbus_connection_call_sync(mConnection.get(),
253 "org.bluez.ProfileManager1",
255 g_variant_new("(osa{sv})", "/org/bluez/spp", "00001101-0000-1000-8000-00805F9B34FB", &builder),
256 nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &errorRegisterCall);
258 auto errorRegisterCallPtr = amb::make_super(errorRegisterCall);
260 if(errorRegisterCallPtr)
262 DebugOut(DebugOut::Error)<<"RegisterProfile failed: "<<errorRegisterCallPtr->message<<endl;
267 bool Bluetooth5::setDevice(string address)
269 mPath = findDevice(address);
274 DebugOut(DebugOut::Error) << "device path not found. Not paired? " << endl;
281 void Bluetooth5::getDeviceForAddress(std::string address, ConnectedCallback connectedCallback)
283 mConnected = connectedCallback;
285 if(!setDevice(address))
288 DebugOut() << "Bluetooth device path: " << mPath << endl;
290 connect(connectedCallback);
293 void Bluetooth5::connected_(int fd)
301 DebugOut(DebugOut::Error) << "Error calling connected callback" << endl;
305 void Bluetooth5::connect(ConnectedCallback onconnectedCallback)
307 mConnected = onconnectedCallback;
309 GError* error = nullptr;
311 auto deviceProxyPtr = amb::make_super(g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,G_DBUS_PROXY_FLAGS_NONE,NULL,
312 "org.bluez", mPath.c_str(), "org.bluez.Device1", nullptr, &error));
314 auto errorPtr = amb::make_super(error);
318 DebugOut(DebugOut::Error) << "Error getting bluetooth device proxy " << errorPtr->message <<endl;
322 g_dbus_proxy_call(deviceProxyPtr.get(), "Connect", nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr,
323 [](GObject *source_object, GAsyncResult *res, gpointer user_data)
326 GError* error = nullptr;
328 g_dbus_proxy_call_finish(G_DBUS_PROXY (source_object), res, &error);
330 auto errorPtr = amb::make_super(error);
334 DebugOut(DebugOut::Warning) << "error trying to connect profile: " << errorPtr->message << endl;
340 void Bluetooth5::disconnect()
342 GError* error = nullptr;
344 auto deviceProxyPtr = amb::make_super(g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,G_DBUS_PROXY_FLAGS_NONE,NULL,
345 "org.bluez", mPath.c_str(), "org.bluez.Device1", nullptr, &error));
347 auto errorPtr = amb::make_super(error);
351 DebugOut(DebugOut::Error) << "Error getting bluetooth device proxy " << errorPtr->message <<endl;
355 g_dbus_proxy_call(deviceProxyPtr.get(), "Disconnect", nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr,[](GObject *source_object,
356 GAsyncResult *res, gpointer user_data){
357 GError* error = nullptr;
359 g_dbus_proxy_call_finish(G_DBUS_PROXY (source_object), res, &error);
361 auto errorPtr = amb::make_super(error);
365 DebugOut(DebugOut::Error) << "error trying to disconnect: " << errorPtr->message << endl;