dbus glib bindings UDisks Error - dbus

void device_added()
{
printf("Added \n");
g_main_loop_quit (loop);
}
void device_removed()
{
printf("Removed\n");
g_main_loop_quit (loop);
}
int
main (int argc, char **argv)
{
DBusGConnection *connection;
DBusMessage* message;
GError *error;
DBusGProxy *proxy;
char **name_list;
char **name_list_ptr;
gchar *m1;
gchar *m2;
g_type_init ();
error = NULL;
connection = dbus_g_bus_get(DBUS_BUS_SYSTEM,NULL);
if (connection == NULL)
{
g_printerr ("Failed to open connection to bus: %s\n",
error->message);
g_error_free (error);
exit (1);
}
/* Create a proxy object for the "bus driver" (name "org.freedesktop.DBus") */
proxy=dbus_g_proxy_new_for_name(connection,"org.freedesktop.UDisks","/org/freedesktop/UDisks","org.freedesktop.UDisks");
if(proxy == NULL)
{
g_printerr ("Failed To Create A proxy...: %s\n", error->message);
g_error_free (error);
exit(1);
}
else
printf("Probably got a connection to the correct interface...\n");
m1=g_cclosure_marshal_VOID__STRING;
m2=g_cclosure_marshal_VOID__STRING;
dbus_g_object_register_marshaller(m1,G_TYPE_BOOLEAN,G_TYPE_STRING,G_TYPE_INVALID);
dbus_g_object_register_marshaller(m2,G_TYPE_BOOLEAN,G_TYPE_STRING,G_TYPE_INVALID);
dbus_g_proxy_add_signal(proxy,"DeviceAdded",G_TYPE_INVALID);
dbus_g_proxy_add_signal(proxy,"DeviceRemoved",G_TYPE_INVALID);
dbus_g_proxy_connect_signal(proxy,"DeviceAdded",(GCallback)device_added,NULL,NULL);
dbus_g_proxy_connect_signal(proxy,"DeviceRemoved",(GCallback)device_removed,NULL,NULL);
loop=g_main_loop_new(NULL,FALSE);
g_main_loop_run (loop);
return 0;
}
I want to detect the usb events, I am using DeviceAdded and DeviceRemoved signals from org.freedesktop.UDisks interface. But device_added or device_removed is not geting called, anybody can you please tell me what's wrong with the above code ?

/*
Compile using the command
* gcc -o dbus-usb dbus-usb.c `pkg-config --libs --cflags dbus-glib-1`
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <glib.h>
#include <glib-object.h>
static GMainLoop *loop;
static void
device_added (DBusGProxy *proxy,
char *ObjectPath[],
char *word_eol[],
guint hook_id,
guint context_id,
gpointer user_data)
{
g_debug("\nAdded a New Device:\nObjectPath: %s\nhook_id: %d\ncontext_id: %d\nuser_data: %d\n", (char*)ObjectPath, hook_id, context_id, (int)user_data);
}
static void
device_removed (DBusGProxy *proxy,
char *ObjectPath[],
char *word_eol[],
guint hook_id,
guint context_id,
gpointer user_data)
{
g_debug("\nRemoved Device\nObjectPath: %s\nhook_id: %d\ncontext_id: %d\nuser_data: %d\n", (char*)ObjectPath, hook_id, context_id, (int)user_data);
}
int
main (int argc, char **argv)
{
DBusGConnection *connection;
DBusMessage* message;
GError *error;
DBusGProxy *proxy;
gchar *m1;
gchar *m2;
char *object_path;
GPtrArray* ret;
g_type_init ();
error = NULL;
connection = dbus_g_bus_get(DBUS_BUS_SYSTEM,NULL);
if (connection == NULL)
{
g_printerr ("Failed to open connection to bus: %s\n",
error->message);
g_error_free (error);
exit (1);
}
else
{
printf("Got a connection to DBUS_BUS_SYSTEM\n");
}
/* Create a proxy object for the "bus driver" (name "org.freedesktop.DBus") */
proxy=dbus_g_proxy_new_for_name(connection,"org.freedesktop.UDisks","/org/freedesktop/UDisks","org.freedesktop.UDisks");
if(proxy == NULL)
{
g_printerr ("Failed To Create A proxy...: %s\n", error->message);
g_error_free (error);
exit(1);
}
else
printf("Probably got a connection to the correct interface...\n");
//It works for me without marsheller register, add and connect to the signals directly
m1=g_cclosure_marshal_VOID__STRING;
m2=g_cclosure_marshal_VOID__STRING;
dbus_g_object_register_marshaller(m1,G_TYPE_NONE,G_TYPE_STRING,G_TYPE_INVALID);
dbus_g_object_register_marshaller(m2,G_TYPE_NONE,G_TYPE_STRING,G_TYPE_INVALID);
dbus_g_proxy_add_signal(proxy,"DeviceAdded",DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
dbus_g_proxy_connect_signal(proxy,"DeviceAdded",(GCallback)device_added,NULL,NULL);
dbus_g_proxy_add_signal(proxy,"DeviceRemoved",DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
dbus_g_proxy_connect_signal(proxy,"DeviceRemoved",(GCallback)device_removed,NULL,NULL);
loop=g_main_loop_new(NULL,FALSE);
g_main_loop_run (loop);
g_error_free (error);
return 0;
}
ABove code is working and able to detect the usb events on Ubuntu pc, major change being the DBUS_TYPE_G_OBJECT_PATH parameter to dbus_g_proxy_add_signal function instead of G_TYPE_STRING.
But if I cross compile for an ARM architecture and execute the same on ARM board, i am facing the same problem again

I got it working on ARM also after starting both
dbus-daemon --system
and
/usr/libexec/udisks-daemon

Related

g_dbus_proxy_new_for_bus_sync: assertion 'g_variant_is_object_path (object_path)' failed

The code following code should retrieve systemd-logind IdleSinceHint property exposed on DBus
/*
* Compile with:
* gcc -Wall print_user_idle_time.c -o print_user_idle_time `pkg-config --libs gio-2.0 --cflags`
*/
#include <gio/gio.h>
static void
print_user_idle_time (GDBusProxy *proxy)
{
gchar *property = "IdleSinceHint";
GError *error = NULL;
GVariant *ret;
guint64 user_idle_time;
ret = g_dbus_proxy_get_cached_property(proxy, property);
if (!ret) {
g_dbus_error_strip_remote_error (error);
g_print ("IdleSinceHint failed: %s\n", error->message);
g_error_free (error);
return;
}
g_variant_get (ret, "(^ao)", &user_idle_time);
g_print("%lu\n", user_idle_time);
g_variant_unref (ret);
}
int
main (int argc, char *argv[])
{
GDBusProxy *proxy;
gchar *name = "org.freedesktop.login1";
gchar *object_path = "org/freedesktop/login1";
gchar *interface_name = "org.freedesktop.login1.Manager";
/* Create a D-Bus proxy */
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
name,
object_path,
interface_name,
NULL, NULL);
g_assert (proxy != NULL);
print_user_idle_time (proxy);
g_object_unref (proxy);
return 0;
}
but when it is runned it fails on assertion g_assert (proxy != NULL); with error
(process:9059): GLib-GIO-CRITICAL **: 17:29:07.245: g_dbus_proxy_new_for_bus_sync: assertion 'g_variant_is_object_path (object_path)' failed
**
ERROR:print_user_idle_time.c:44:main: assertion failed: (proxy != NULL)
What can be the problem? Thank you
The issue you are seeing is that object paths must start with '/' so it's /org/freedesktop/login1.
In addition to that, the property GVariant handling line looks out of place. This should be enough:
user_idle_time = g_variant_get_uint64 (ret);

DBus: Watch when name disappears from bus

I am implimenting the StatusNotifierWatcher service using the low-level DBus C library. The StatusNotifierWatcher specification requires that the watcher can know when "A StatusNotifierItem instance has disappeared from the bus" So that it can send the StatusNotifierItemUnregistered signal.
An example implimentation:
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>
DBusConnection *conn = NULL;
void item_unregistered_signal(const char *name) {
DBusMessage *signal = dbus_message_new_signal(
"/org/freedesktop/StatusNotifierWatcher",
"org.freedesktop.StatusNotifierWatcher",
"StatusNotifierItemUnregistered");
dbus_message_append_args(signal,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);
dbus_connection_send(conn, signal, NULL);
dbus_message_unref(signal);
}
void watch_name(const char *name, void(*cb)(const char *)) {
// Not sure how to impliment
}
dbus_bool_t register_item(DBusConnection *connection, DBusMessage *message, void *_data) {
DBusError error;
char *name;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Error parsing method args: %s\n", error.message);
return FALSE;
}
watch_name(name, item_unregistered_signal);
return TRUE;
}
static void check_and_abort(DBusError *error) {
if (dbus_error_is_set(error)) {
fprintf(stderr, "dbus_err: %s\n", error->message);
exit(EXIT_FAILURE);
}
}
int main() {
DBusError error;
dbus_error_init(&error);
conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
check_and_abort(&error);
dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher",
DBUS_NAME_FLAG_REPLACE_EXISTING,
&error);
check_and_abort(&error);
dbus_connection_add_filter(conn, register_item, NULL, free);
while(1) {
dbus_connection_read_write_dispatch(conn, 1000);
}
}
If I have the well-known name to a DBus service, how do I know when the name disappears from the bus?
Well, I figured this out and I'll post an answer for any future poor souls who need to work with libdbus.
org.freedesktop.DBus sends the NameOwnerChanged signal whenever any DBus name changes. One can use this signal to track if an item has disappeared because the NewOwner argument is a null string.
This function can do that:
static DBusHandlerResult signal_handler(DBusConnection *connection,
DBusMessage *message, void *_usr_data) {
if (dbus_message_is_signal(message, "org.freedesktop.DBus",
"NameOwnerChanged")) {
const char *name;
const char *old_owner;
const char *new_owner;
if (!dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old_owner,
DBUS_TYPE_STRING, &new_owner,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Error getting OwnerChanged args");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (strcmp(name, "") != 0) {
// Name not lost, just swapped owners
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
name_lost(name);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
One also needs to add a match so that your program will be called with this signal. I added this in main()
dbus_bus_add_match(conn,
"type='signal',\
sender='org.freedesktop.DBus',\
interface='org.freedesktop.DBus',\
member='NameOwnerChanged'",
&error);
check_and_abort(&error);
dbus_connection_add_filter(conn, signal_handler, NULL, free);
For those using GDBus (recommended) instead of libdbus (discouraged), the equivalent is g_bus_watch_name().

Using GStreamer to play raw PCM-data

Ok, I have written some code below that is supposed to open and audio output device, and whenever actual PCM-data is available I would call Sound_WriteFrame() and pile up more data to be played.
The data is raw, with no headers, so when I call Sound_Open() I pass this information to let GStreamer know what kind of data that will arrive.
This code does not work - Frankly I have no idea what I am doing, I find GStreamer a bit difficult to work with, I would hope that could change eventually.
I am using GStreamer 1.0. Help is appreciated.
#include <gstreamer-1.0/gst/gst.h>
#include <gstreamer-1.0/gst/gstelement.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
typedef struct _sound_t {
GstElement *source, *sink, *pipeline;
GMemoryInputStream *giostream;
GstPad *sourcepad;
GstCaps *gcaps;
int bDeviceOpen;
} SOUND_CTX;
int Sound_Close(SOUND_CTX *p){
printf("Closing\n");
gst_element_set_state(p->pipeline, GST_STATE_NULL);
return 1;
}
void Sound_SetState(SOUND_CTX *p, GstState state){
GstStateChangeReturn r = gst_element_set_state(p->pipeline, state);
switch(r){
case GST_STATE_CHANGE_FAILURE: printf("GST_STATE_CHANGE_FAILURE\n"); break;
case GST_STATE_CHANGE_SUCCESS: printf("GST_STATE_CHANGE_SUCCESS\n"); break;
case GST_STATE_CHANGE_ASYNC: printf("GST_STATE_CHANGE_ASYNC\n"); break;
case GST_STATE_CHANGE_NO_PREROLL: printf("GST_STATE_CHANGE_NO_PREROLL\n"); break;
default: printf("Unknown state\n"); break;
}
return;
}
int Sound_Open(SOUND_CTX *p, int nSamplesPerSec, int nChannels){
p->source = gst_element_factory_make("giostreamsrc", "source");
p->giostream = G_MEMORY_INPUT_STREAM(g_memory_input_stream_new());
g_object_set(G_OBJECT(p->source), "stream", G_INPUT_STREAM(p->giostream), NULL);
p->sourcepad = gst_element_get_static_pad(p->source, "src");
p->gcaps = gst_caps_new_simple(
"audio/x-raw",
"rate", G_TYPE_INT, nSamplesPerSec,
"channels", G_TYPE_INT, nChannels,
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16,
"signed", G_TYPE_BOOLEAN, TRUE,
NULL
);
gst_pad_set_caps(p->sourcepad, p->gcaps);
gst_object_unref(p->sourcepad);
p->sink = gst_element_factory_make("alsasink", "sink");
p->pipeline = gst_pipeline_new("pipeline_name");
gst_bin_add_many(GST_BIN(p->pipeline), p->source, p->sink, NULL);
gst_element_link_many(p->source, p->sink, NULL);
Sound_SetState(p, GST_STATE_PLAYING);
return 1;
}
int Sound_WriteFrame(SOUND_CTX *p, void *lpData, unsigned int size){
g_memory_input_stream_add_data(
G_MEMORY_INPUT_STREAM(p->giostream),
lpData, size, NULL
);
return 0;
}
int timer_callback(const void *data){
g_main_loop_quit((GMainLoop *)data);
return FALSE;
}
int main(int argc, char *argv[]){
gst_init(&argc, &argv);
GMainLoop *loop = NULL;
SOUND_CTX a;
memset(&a, 0x00, sizeof(SOUND_CTX));
if(Sound_Open(&a, 44100, 2)){
FILE *handle;
unsigned char tmp[4096];
if((handle = fopen("test.pcm", "rb")) != NULL){
while(fread(tmp, 1, sizeof(tmp), handle) == sizeof(tmp)){
Sound_WriteFrame(&a, tmp, sizeof(tmp));
}
fclose(handle);
}
}
loop = g_main_loop_new(NULL, FALSE);
g_timeout_add(5500, (GSourceFunc)timer_callback, loop);
g_main_loop_run(loop);
Sound_Close(&a);
g_main_loop_unref(loop);
return 0;
}
Ok, so here is an updated source, there is however no sound coming out of the speakers
#include <gstreamer-1.0/gst/gst.h>
#include <gstreamer-1.0/gst/gstelement.h>
#include <gstreamer-1.0/gst/app/gstappsrc.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
typedef struct _sound_t {
GstElement *sink, *pipeline;
GstAppSrc *src;
GstCaps *pcm_caps;
} SOUND_CTX;
int Sound_Close(SOUND_CTX *p){
printf("Closing\n");
gst_element_set_state(p->pipeline, GST_STATE_NULL);
return 1;
}
void Sound_SetState(SOUND_CTX *p, GstState state){
GstStateChangeReturn r = gst_element_set_state(p->pipeline, state);
switch(r){
case GST_STATE_CHANGE_FAILURE: printf("GST_STATE_CHANGE_FAILURE\n"); break;
case GST_STATE_CHANGE_SUCCESS: printf("GST_STATE_CHANGE_SUCCESS\n"); break;
case GST_STATE_CHANGE_ASYNC: printf("GST_STATE_CHANGE_ASYNC\n"); break;
case GST_STATE_CHANGE_NO_PREROLL: printf("GST_STATE_CHANGE_NO_PREROLL\n"); break;
default: printf("Unknown state\n"); break;
}
return;
}
int Sound_Open(SOUND_CTX *p, int nSamplesPerSec, int nChannels){
p->pipeline = gst_pipeline_new("pipeline_name");
p->sink = gst_element_factory_make("alsasink", "sink");
p->src = (GstAppSrc*) gst_element_factory_make("appsrc", "source");
gst_app_src_set_stream_type(p->src, GST_APP_STREAM_TYPE_STREAM);
// I am hardcoding the format, channels, and rate for now
p->pcm_caps = gst_caps_from_string("audio/x-raw,format=S16LE,rate=44100,channels=2");
gst_app_src_set_caps(p->src, p->pcm_caps);
gst_bin_add_many(GST_BIN(p->pipeline), (GstElement*)p->src, p->sink, NULL);
gst_element_link_many((GstElement*)p->src, p->sink, NULL);
Sound_SetState(p, GST_STATE_PLAYING);
return 1;
}
int Sound_WriteFrame(SOUND_CTX *p, void *lpData, unsigned int size){
GstBuffer *buf = NULL;
void *lpHeapData = NULL;
if((lpHeapData = g_malloc(size)) == NULL) return 0;
memcpy(lpHeapData, lpData, size);
buf = gst_buffer_new_wrapped(lpHeapData, size);
if(buf == NULL){
g_free(lpHeapData);
return 0;
}
gst_app_src_push_buffer(p->src, buf);
return 0;
}
int timer_callback(const void *data){
g_main_loop_quit((GMainLoop *)data);
return FALSE;
}
int main(int argc, char *argv[]){
gst_init(&argc, &argv);
GMainLoop *loop = NULL;
SOUND_CTX a;
memset(&a, 0x00, sizeof(SOUND_CTX));
if(Sound_Open(&a, 44100, 2)){
FILE *handle;
unsigned char tmp[4096];
if((handle = fopen("test.pcm", "rb")) != NULL){
while(fread(tmp, 1, sizeof(tmp), handle) == sizeof(tmp)){
Sound_WriteFrame(&a, tmp, sizeof(tmp));
}
fclose(handle);
}
}
loop = g_main_loop_new(NULL, FALSE);
g_timeout_add(5500, (GSourceFunc)timer_callback, loop);
g_main_loop_run(loop);
Sound_Close(&a);
g_main_loop_unref(loop);
return 0;
}
You are using GStreamer 0.10 Caps fields in something that looks like GStreamer 1.0 Code. For you interest, width/depth/signed has been replaced by a single field called format. See the documentation for the complete list, the name in caps is the same as the enumeration, but without the namespace GST_AUDIO_FORMAT_.
https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudio.html#GstAudioFormat

Connecting to Bluetooth Device using bluetooth_client_connect_service() - gnome-bluetooth 3.8.2.1

I would be glad if I can be pointed in the right direction the community concerning my above topic.
I am interested in connecting to bluetooth devices using the gnome-bluetooth api in ubuntu 14.04 using the bluetooth_client_connect_service() function.
I have tried searching but could not find good results on how to use it so I decided to read the gnome-bluetooth's source code but due to insufficient commenting I am unable to understand.
Below is what I have done so far but I do not get any errors when I try running my application yet when I double-click on a device it does nothing.
#define AGENT_PATH "/org/bluez/agent/wizard"
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <signal.h>
#include <math.h>
#include <glib.h>
//#include <dbus/dbus.h>
#include <glib/gi18n.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <bluetooth-chooser.h>
#include <bluetooth-client.h>
#include <bluetooth-utils.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#define CONNECT_TIMEOUT 3.0
#define AGENT_PATH "/org/bluez/agent/wizard"
typedef struct {
char *path;
GTimer *timer;
} ConnectData;
BluetoothClient *client;
GtkWidget *selector;
GtkWidget *vboxMainLayout;
GValue value = { 0, };
int find_conn(int s, int dev_id, long arg)
{
struct hci_conn_list_req *cl;
struct hci_conn_info *ci;
int i;
if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) {
perror("Can't allocate memory");
exit(1);
}
cl->dev_id = dev_id;
cl->conn_num = 10;
ci = cl->conn_info;
if (ioctl(s, HCIGETCONNLIST, (void *) cl)) {
perror("Can't get connection list");
exit(1);
}
for (i = 0; i < cl->conn_num; i++, ci++)
if (!bacmp((bdaddr_t *) arg, &ci->bdaddr)) {
free(cl);
return 1;
}
free(cl);
return 0;
}
void cmd_rssi(const char *bt_address)
{
struct hci_conn_info_req *cr;
bdaddr_t bdaddr;
int8_t rssi;
int dd, dev_id;
str2ba(bt_address, &bdaddr);
dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
if (dev_id < 0) {
g_print("\tNot connected.\n");
return;
}
dd = hci_open_dev(dev_id);
if (dd < 0) {
perror("HCI device open failed");
exit(1);
}
cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
if (!cr) {
perror("Can't allocate memory");
exit(1);
}
bacpy(&cr->bdaddr, &bdaddr);
cr->type = ACL_LINK;
if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
perror("Get connection info failed");
exit(1);
}
if (hci_read_rssi(dd, htobs(cr->conn_info->handle), &rssi, 1000) < 0) {
perror("Read RSSI failed");
exit(1);
}
g_print("\tRSSI return value: %d\n", rssi);
free(cr);
hci_close_dev(dd);
}
void connect_callback (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
ConnectData *data = (ConnectData *) user_data;
gboolean success;
success = bluetooth_client_connect_service_finish (client, res, NULL);
if (success == FALSE && g_timer_elapsed (data->timer, NULL) < CONNECT_TIMEOUT) {
bluetooth_client_connect_service (client, data->path, TRUE, NULL, connect_callback, data);
return;
}
if (success == FALSE)
g_print ("\tFailed to connect to device %s", data->path);
else
g_print("\n\tConnection successfully.. ha.. I'm tired\n");
g_timer_destroy (data->timer);
g_free (data->path);
g_free (data);
}
void create_callback (BluetoothClient *_client, const char *path, const GError *error, gpointer user_data)
{
ConnectData *data;
//compiler throws "implicit declaration" warning here
//bluetooth_client_set_trusted(client, path, TRUE);
data = g_new0 (ConnectData, 1);
data->path = g_strdup (path);
data->timer = g_timer_new ();
bluetooth_client_connect_service (client, path, TRUE, NULL, connect_callback, data);
}
void get_device_info(BluetoothChooser *self)
{
const gchar* result;
g_print ("Info dumped:\n");
if (bluetooth_chooser_get_selected_device_info (self, "name", &value)) {
g_print ("\tName: '%s'\n", g_value_get_string (&value));
g_value_unset (&value);
}
if (bluetooth_chooser_get_selected_device_info (self, "address", &value)) {
g_print ("\tAddress: '%s'\n", g_value_get_string (&value));
g_value_unset (&value);
}
if (bluetooth_chooser_get_selected_device_info (self, "paired", &value)) {
result = g_value_get_boolean (&value)? "Paired":"Unpaired";
g_print ("\tPaired: '%s'\n", result);
g_value_unset (&value);
}
guint type = bluetooth_chooser_get_selected_device_type (self);
const gchar *device_type = bluetooth_type_to_string(type);
if(type)
{
g_print("\tType: '%s'\n", device_type);
}
if (bluetooth_chooser_get_selected_device_info (self, "connected", &value)) {
result = g_value_get_boolean (&value)? "Connected":"Not Connected";
g_print ("\tConnected: '%s'\n", result);
g_value_unset (&value);
}
}
/* My problem lies here.. how to connect to the detected device
* no error message is displayed when a device is double-clicked
*/
void connect_button_clicked(GtkWidget *widget, gpointer user_data)
{
const char *path = AGENT_PATH;
ConnectData *data = (ConnectData *) user_data;
GValue value = { 0, };
bluetooth_chooser_get_selected_device_info (widget, "address", &value);
bluetooth_client_connect_service (client, path, TRUE, NULL, connect_callback, data);
//function to get the rssi value of the remote device
cmd_rssi(g_value_get_string (&value));
}
void create_interface(GtkApplication *app, gpointer user_data)
{
GtkWidget *frmTopWindow;
frmTopWindow = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(frmTopWindow), "Test");
gtk_window_set_position(GTK_WINDOW(frmTopWindow),GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(frmTopWindow),200,400);
selector = bluetooth_chooser_new();
g_object_set(selector,
"show-searching", TRUE,
"show-device-type", FALSE,
"show-pairing" , TRUE,
"show-device-category", FALSE,
NULL);
client = bluetooth_client_new();
vboxMainLayout = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3);
g_object_set(vboxMainLayout,
"width-request", 190,
"height-request", 300, NULL);
gtk_container_add(GTK_CONTAINER(frmTopWindow),selector);
/*Events and Signals*/
/*------------------*/
// When user double-clicks on a detected device, try and connect to that device
// and display it's RSSI
g_signal_connect(G_OBJECT(selector),"notify::selected-device-activated",G_CALLBACK(connect_button_clicked),client);
//When user clicks on a detected device, display information about that device in the
// standard output
g_signal_connect(G_OBJECT(selector),"notify::device-selected",G_CALLBACK(get_device_info),vboxMainLayout);
gtk_widget_show_all(frmTopWindow);
}
int main(int argc, char** argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("rucst.project.test", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (create_interface), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
In my implementation code, I have a g_signal_connect function that calls it as shown below:
g_signal_connect(G_OBJECT(selector),"notify::selected-device-activated",G_CALLBACK(connect_button_clicked),client);
This code I expect to connect to the selected detected device when it receives a double-click signal but at the moment nothing happens when I double-click on it.
I would be very grateful to receive guidance from the experts.
Thank you in advance
g_signal_connect(G_OBJECT(selector),"notify::selected-device-activated",
G_CALLBACK(connect_button_clicked),client);
This signal signature would be used if there was a property "selected-device-activated" and you wanted to know when the property value changes. But in this case "selected-device-activated" is an actual signal so you should just do:
g_signal_connect(G_OBJECT(selector),"selected-device-activated",
G_CALLBACK(callback), client);
The single click version just happens to work because you've found a property that does what you want, so connecting to "notify::device-selected" works (I'd still connect to the "selected-device-changed" signal for consistency instead).
After that in connect_button_clicked() your connect call uses what seems like a an unrelated path as the device object path... Something like this might work instead (although I'm not 100% sure about the "proxy" field name, I've not used this API myself):
GValue value = { 0, };
if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (widget),
"proxy", &value)) {
GDBusProxy *proxy = g_value_get_object (&value);
g_print ("Connecting to %s\n", g_dbus_proxy_get_object_path(proxy));
bluetooth_client_connect_service (client, g_dbus_proxy_get_object_path(proxy),
TRUE, NULL, connect_callback, data);
}
Note also that the userdata pointers you give to the callbacks are wrong: e.g. connect_button_clicked() expects a ConnectData* but gets a BluetoothClient*.

Glib/Gio Asynchronous or Threaded UDP Server

I have currently a synchronous UDP application receiving messages.
The code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include <gio/gio.h>
int main(argc,argv)
int argc;
char ** argv;{
char buf[256], *ptr, sep[] = "| ";
GError * error = NULL;
GSocket * socket;
GSocketAddress *gsockAddr, *gfromAddr;
guint16 udp_port = 1500;
//Creates socket udp ipv4
socket = g_socket_new(G_SOCKET_FAMILY_IPV4,
G_SOCKET_TYPE_DATAGRAM,
G_SOCKET_PROTOCOL_UDP,
&error);
g_assert(error == NULL);
if (socket == NULL) {
g_print("ERROR");
exit(1);
}
//sockaddr struct like
gsockAddr = G_SOCKET_ADDRESS(g_inet_socket_address_new(g_inet_address_new_any(G_SOCKET_FAMILY_IPV4), udp_port));
if(gsockAddr == NULL){
g_error("Error socket\n");
exit(1);
}
//
if (g_socket_bind (socket, gsockAddr, TRUE, NULL) == FALSE){
g_print("Error bind\n");
exit(1);
}
int bytes = g_socket_receive_from (socket,
&gfromAddr,
buf,
255,
NULL,
&error);
if (bytes == -1) {
g_warning ("Failed to receive from socket: %s", error->message);
g_error_free (error);
return TRUE;
}
g_message("Server receive: %s", buf);
guint16 port = g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(gfromAddr));
g_print("...from %s(%d)\n",g_inet_address_to_string(g_inet_socket_address_get_address(G_INET_SO CKET_ADDRESS(gfromAddr))), (int) port);
exit(0);
}
So, I want to make the receive operation, non-blocking instead of blocking. I want to make it either ansynchronous, or/and threaded so that, meanwhile, I could do other operations related to the application I want to develop.
But I did not suceed to make it like I want. I tried to use GLib IO Channels, but I can not make it works. The processus is waiting, but only because of the Main Loop (I can not telnet the application).
The code :
#include <gio/gio.h>
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BLOCK_SIZE 1024
static gboolean
gio_read_socket (GIOChannel *channel,
GIOCondition condition,
gpointer data)
{
char buf[1024];
gsize bytes_read;
GError *error = NULL;
if (condition & G_IO_HUP) return FALSE; /* this channel is done */
g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read,
&error);
g_assert (error == NULL);
buf[bytes_read] = '\0';
g_print ("%s", buf);
return TRUE;
}
int
main (int argc, char **argv)
{
GSocket * s_udp;
GError *err = NULL;
guint16 udp_port = 5556;
s_udp = g_socket_new(G_SOCKET_FAMILY_IPV4,
G_SOCKET_TYPE_DATAGRAM,
G_SOCKET_PROTOCOL_UDP,
&err);
g_assert(err == NULL);
if (s_udp == NULL) {
g_print("ERROR");
exit(1);
}
g_socket_bind(s_udp,
G_SOCKET_ADDRESS(g_inet_socket_address_new(g_inet_address_new_any(G_SOCKET_FAMILY_IPV4), udp_port)),
TRUE,
&err);
g_assert(err == NULL);
int fd = g_socket_get_fd(s_udp);
GIOChannel* channel = g_io_channel_unix_new(fd);
guint source = g_io_add_watch(channel, G_IO_IN,
(GIOFunc) gio_read_socket, NULL);
g_io_channel_unref(channel);
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
g_main_loop_unref(loop);
}
I am quite a beginner with GLib/Gio, and I think I am doing wrong with the IO Channels. I would like to add it to the main loop as an event, so that I could use my callback function. Maybe there is a simpler way to do that.
Besides, I have a TCP asynchronous and threaded server that is working, but I did not find how to do the same with UDP (using a GThreadedSocketService and creating a socket listener, then adding the service to the main loop. Easy as pie with TCP).
Do you have any idea how to proceed ? If you know how to do but only with the basic API socket, I still take it ! Thanks.
I figure it out.
I am indeed quite a beginner. Because, when I wanted to test my udp application (the second code block), I used telnet to connect to it and try to send messages. However, we can not telnet udp applications of course...
So I tried with a simple udp sender (I used Glib/Gio for it by the way) instead of telnet and it worked, perfectly non-blocking and reusable. I did make some changes but basically, it is the same. I put an idle function to show you how non-blocking it is, whether this can help someone one day.
My simple Glib/Gio UDP app, non blocking :
#include <gio/gio.h>
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BLOCK_SIZE 1024
static gboolean
gio_read_socket (GIOChannel *channel,
GIOCondition condition,
gpointer data)
{
char buf[1024];
gsize bytes_read;
GError *error = NULL;
if (condition & G_IO_HUP) return FALSE; /* this channel is done */
g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read,
&error);
g_assert (error == NULL);
buf[bytes_read] = '\0';
g_print ("%s", buf);
int *a = data;
*a = *a + 1;
return TRUE;
}
gboolean
idleCpt (gpointer user_data){
int *a = user_data;
g_print("%d\n", *a);
sleep(1);
return TRUE;
}
int
main (int argc, char **argv)
{
GSocket * s_udp;
GError *err = NULL;
int idIdle = -1, dataI = 0;
guint16 udp_port = 1505;
GSocketAddress * gsockAddr = G_SOCKET_ADDRESS(g_inet_socket_address_new(g_inet_address_new_any(G_SOCKET_FAMILY_IPV4), udp_port));
s_udp = g_socket_new(G_SOCKET_FAMILY_IPV4,
G_SOCKET_TYPE_DATAGRAM,
G_SOCKET_PROTOCOL_UDP,
&err);
g_assert(err == NULL);
if (s_udp == NULL) {
g_print("ERREUR");
exit(1);
}
if (g_socket_bind (s_udp, gsockAddr, TRUE, NULL) == FALSE){
g_print("Erreur bind\n");
exit(1);
}
g_assert(err == NULL);
int fd = g_socket_get_fd(s_udp);
GIOChannel* channel = g_io_channel_unix_new(fd);
guint source = g_io_add_watch(channel, G_IO_IN,
(GIOFunc) gio_read_socket, &dataI);
g_io_channel_unref(channel);
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
idIdle = g_idle_add(idleCpt, &dataI);
g_main_loop_run(loop);
}
The code is not perfect, there is a lot of optimisations to make, but we can do nice things from that I think. If you want to see my udp sender, just ask.

Resources